# การป้องกันความลับหลุดตอนที่ 1

## 😢 ปัญหา

ในการเขียนแอพอะไรก็ตาม ในบางทีตัวแอพของเราก็อาจจะต้องมีการเชื่อมต่อกับภายนอก เช่น ฐานข้อมูล, API หรืออะไรก็ตามแต่ ซึ่งการเชื่อมไปที่ต่างๆเหล่านั้น มันจำเป็นที่เราจะต้องใส่ **`รหัสลับ`** ของเราลงไป เพื่อให้มันสามารถเชื่อมไปยังที่อื่นๆได้ เช่น **ConnectionString** ที่เอาไว้ต่อฐานข้อมูล หรือ **Username & Password** ในการเข้าใช้งานระบบอื่นๆ แล้วเราจะเก็บความลับพวกนั้นไว้ในแอพของเราได้ยังไง โดยไม่ให้มันหลุดออกไป เพราะเราคงไม่อยากให้ฐานข้อมูลของเรามีใครก็ไม่รู้เข้าใจดูหรือแก้ไขอะไรเล่นๆแน่นอนชิมิ ?

{% hint style="danger" %}
**คำเตือน**\
ในบางทีเราก็จะไม่ใส่รหัสลับพวกนั้นลงไปในแอพของเรา แต่เราจะแจกให้กับคนในทีมเพื่อให้เพื่อนๆในทีมสามารถเข้าไปจัดการแก้ไขได้ แต่ก็อย่าลืมนะว่า **รหัสลับมันอาจจะรั่วเพราะคนในทีมเราเองก็ได้ และ เลวร้ายยิ่งกว่าคือเขาอาจจะเป็นคนร้ายเองก็เป็นได้**
{% endhint %}

{% hint style="success" %}
**แนะนำให้อ่าน**\
บทความนี้เป็นส่วนหนึ่งของคอร์ส [🤠 **Cloud Playground**](https://www.saladpuk.com/cloud/cloud-playground) ที่จะพาเพื่อนๆแมวน้ำทั้งหลายได้ลองมาดูว่า การสร้างโปรเจคเพื่อทำงานบนคลาว์ โดยใช้มาตรฐานสากลจริงๆแล้วเขาทำกันยังไง ส่วนถ้าสนใจอยากอ่านต่อก็กดไปที่ลิงค์สีฟ้าๆได้เลย
{% endhint %}

จากที่ว่ามาเดี๋ยวเราจะค่อยๆดูตัวเลือกของเราไปทีละตัวละกันว่ามันมีเรื่องอะไรมาช่วยเราได้บ้าง ซึ่งแต่ละตัวระดับความเข้มงวดของมันก็จะใช้ตามแต่ละสถานะการณ์ของมันไป

## 😘 เข้าใจให้ตรงกันก่อน

{% hint style="info" %}
ข้ามไปอ่านหัวข้อถัดไปได้เลยถ้าใครใช้ asp.net core api เป็นอยู่แล้ว
{% endhint %}

ตัวอย่างในบทความนี้ผมจะสร้างเว็บโดยใช้ **`asp.net core (API)`** เป็นพื้นฐาน และใช้ **`Visual Studio Code`** ในการเดโม่ทั้งหมด ดังนั้นถ้าใครอยากจะทำตามก็ไปติดตั้งของต่างๆให้เรียบร้อยแซ๊ะ หรือถ้าขี้เกียจติดตั้งก็โหลดไฟล์เว็บด้านล่างนี้ไปแล้วข้ามไปดูหัวข้อถัดไปเลย

{% file src="<https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-M-YGbmCN_bUNNTWEX8y%2F-M-YIHfOIEYan9zP-sLJ%2Fsaladpuk-demo.zip?alt=media&token=4bdbaf69-6e82-49f5-ac63-23a392156df2>" %}
ASP.NET Core
{% endfile %}

การสร้างโปรเจค asp.net core ก็สร้างโดยใช้คำสั่งพื้นฐานด้านล่างธรรมดาแหละ โดยผมจะสร้างเป็นตัว web api ละกันจะได้อธิบายง่ายๆหน่อย

```
dotnet new api -n saladpuk-demo
```

เพียงเท่านี้เราก็จะได้โปรเจคพื้นฐานมาเรียบร้อยละ

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-M1lfqlFTvI3gmheTI_q%2F-M1On8wpN8NpAAKXXYjl%2Fimage.png?generation=1583529175316566\&alt=media)

ตัวเว็บที่เราได้มาในโฟเดอร์ `Controllers` จะมีไฟล์ **`WeatherForecastController`** ที่เขาใส่ไว้เป็นพื้นฐาน เพื่อจำลองการพยากรณ์อากาศเอาไว้ ดังนั้นเราก็จะลองใช้คำสั่งด้านล่าง เพื่อทำการเปิดเว็บตัวนี้ขึ้นมา

```
dotnet run
```

แล้วก็เข้าไปดูเว็บของเราด้วย URL ตัวนี้ <https://localhost:5001/WeatherForecast> ซึ่งมันก็จะโชว์ข้อมูลจำลอง Json ออกมาประมาณนี้

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-M1lfqlFTvI3gmheTI_q%2F-Lrx_cxTBZGDqQECAR5t%2Fimage.png?generation=1583529135724863\&alt=media)

ก็เป็นอันจบว่าเรามีตัวเว็บที่พร้อมเอาไว้เล่นกันต่อละ

## 💔 ตัวอย่างปัญหา

สมมุติว่าตัวเว็บของเราต้องไปดึงข้อมูลพยากรณ์อากาศจาก database เพื่อเอามาโชว์ให้ผู้ใช้ละกัน ผมก็จะเข้าไปแก้ไฟล์ **`WeatherForecastController`** เป็นราวๆนี้ละกัน

```csharp
public IEnumerable<WeatherForecast> Get()
{
    var dbConnectionString = "รหัสลับในการต่อฐานข้อมูล";
    // จำลองว่าไปดึงข้อมูลจาก db มาแล้วได้ตัวนี้นะ
    var result = new[]
    {
        new WeatherForecast
        { 
            Date = DateTime.Now, 
            TemperatureC = 20, 
            Summary = "Balmy" 
        }
    };
    return result;
}
```

จากโค้ดตัวอย่างด้านบนเราจะเห็นว่าบรรทัดที่ 3 โค้ดของเรามีการฝัง **`ConnectionString`** ที่เป็นความลับเอาไว้ ซึ่งถ้าไม่มีเราก็จะไม่สามารถต่อฐานข้อมูลได้นั่นเอง ซึ่งถ้าเราปล่อยไว้แบบนี้มันจะเกิดปัญหาคือ

* ถ้าเราอยากจะแก้ไขรหัสลับตัวนี้ เราก็จะต้อง build & deploy project ใหม่เท่านั้น
* ใน source code ของเรามีความลับติดไปด้วยกับการ commit เสมอ ยิ่งถ้า repository ของเราเป็น public แล้วล่ะก็ ทุกคนบน GitHub ก็จะส่งยิ้มอ่อนให้เรา เพราะเขาก็เข้าฐานข้อมูลเราเช่นกัน
* Developer ทุกคนเห็นความลับนี้หมด ดังนั้นใครจะเข้าฐานข้อมูลก็ได้
* และอื่นๆนาๆ ที่เดี๋ยวจะมาเติมในบทความถัดๆไป

จากที่ร่ายมาก็จะเห็นว่ามันมีปัญหาหลายเรื่องม๊วกๆ ดังนั้นเราจะค่อยแก้ไปทีละเรื่องกันนะ

## 🤠 วิธีแก้ปัญหา (การตั้งค่าความลับ)

ตัวแรกที่แก้ได้ง่ายที่สุดก็คือ ทำให้เราแก้ไข configuration ต่างได้ง่ายๆ โดยไม่ต้อง Build & Deploy ตัวเว็บใหม่ดีกว่า โดยถ้าเราดูที่ตัวโปรเจคของเราดีๆ เราจะเห็นไฟล์ที่ชื่อว่า **`appsettings.json`** นั่นเอง ซึ่งเจ้าตัวนี้มีหน้าที่เอาไว้ทำการ config ของต่างๆให้กับโปรเจคนั่นเอง ดังนั้นเราจะย้ายความลับของเราออกจากไฟล์ `.cs` ไปไว้ที่ **appsettings.json** แทนตามโค้ดด้านล่าง

```typescript
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "DbConnectionString" : "ABCDEFG"
}
```

จากโค้ดด้านบน ผมเพิ่มบรรทัดที่ 10 เข้าไป โดยตั้งชื่อมันว่า **`DbConnectionString`** และให้มันเก็บรหัสลับในการต่อฐานข้อมูลลงไป (ในตัวอย่างผมให้รหัสลับเป็น ABCDEFG นะ)

โดยปรกติตัว asp.net core มันจะอ่านไฟล์ **appsettings.json** ตอนเริ่มเว็บด้วยเสมอ ดังนั้นถัดไปผมก็จะแก้ไฟล์ **`WeatherForecastController`** ให้มันรับ **`IConfiguration`** เข้าไปใน constructor นั่นเอง ตามนี้

```csharp
public class WeatherForecastController : ControllerBase
{
    private readonly IConfiguration configuration;

    public WeatherForecastController(IConfiguration configuration)
    {
        this.configuration = configuration;
    }

    ...
}
```

{% hint style="info" %}
**หมายเหตุ**\
ตัว asp.net core มันจะอ่าน **Environment Variables** ขึ้นมา ซึ่งเราสามารถดูค่าพวกนั้นได้โดยใช้ **IConfiguration** ซึ่งโดยปรกติตัว asp.net core มันจะมีตัว **Dependency Injection (DI)** คอยส่ง object ของ IConfiguration มาให้เราอยู่แล้วโดยที่เราไม่ต้องไปทำอะไรเพิ่มเติมเลยครัช
{% endhint %}

สุดท้ายเพื่อให้เห็นภาพได้ง่ายว่าตัวเว็บเราสามารถอ่านค่าความลับที่เราเก็บไว้ใน **appsettings.json** ได้ เราก็ลองเอามันมาโชว์ดู โดยการเพิ่ม api เข้าไปนิสนุงตามด้านล่าง

```csharp
[HttpGet("secret")]
public string Secret()
{
    return configuration["DbConnectionString"];
}
```

คราวนี้เราลองเรียกตัว api ตัวใหม่นี้ดู โดยการเปิด URL ตัวนี้ <https://localhost:5001/WeatherForecast/secret> เราก็จะพบว่าตัว api ของเรานั้นมันจะเอาค่าที่อยู่ใน **appsettings.json** มาแสดงให้เราเรียบร้อยแล้ว ตามรูปด้านล่าง

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-M1lfqlFTvI3gmheTI_q%2F-LofDr6LI61lf8JhLbC4%2Fimage.png?generation=1583529170344596\&alt=media)

{% hint style="success" %}
**ข้อดีในการทำแบบนี้**\
ตัวเว็บของเราเมื่อต้องการแก้ไขค่า configuration ต่างๆก็สามารถทำได้เลย โดยที่ไม่ต้องไป build & deploy ใหม่นั่นเอง
{% endhint %}

{% hint style="danger" %}
**ข้อควรระวัง**\
จากที่ทำมาทั้งหมดนี้ มันจะยังไม่ได้แก้ปัญหาเรื่องเราฝังความลับของเราไว้ที่ source code นะ แม้ว่ามันจะไม่อยู่ในไฟล์ **.cs** แล้วก็ตาม แต่ตัวความลับของเราก็ยังอยู่ในไฟล์ **appsettings.json** นั่นเอง ถ้าเรา commit ไฟล์นี้ขึ้นไป มันก็จะติดอยู่ใน history ต่อไปอยู่ดีนั่นเอง
{% endhint %}

## 🤠 วิธีแก้ปัญหา (แยกความลับออกจาก source code)

ถัดมาเราก็จะลองทำให้ความลับของเราไม่อยู่ติดไปกับ source code ของเรากันดีกว่า ซึ่งโดยปรกติตัวเครื่องคอมของเรามันจะมีสิ่งที่เรียกว่า **`Environment Variables`** อยู่ ซึ่งเราสามารถหามันได้จากการกดปุ่ม Windows แล้วหาคำว่า Environment Variables ตามรูปด้านล่างนั่นเอง

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-M1lfqlFTvI3gmheTI_q%2F-M0OMNqE46O4KkPoGzPy%2Fimage.png?generation=1583529168109528\&alt=media)

ซึ่งเมื่อเปิดขึ้นมาแล้ว เราก็จะเข้าไปกำหนดค่า **Environment Variables** (อันเดียวกับที่เรากำหนด path ให้ java ยังไงล่ะ)

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-M1lfqlFTvI3gmheTI_q%2F-M1lg0cd6MD_PTP1FIvC%2Fimage%20\(959\).png?generation=1583529180833079\&alt=media)

ถัดมาเราก็จะทำการสร้าง Environment Variable ของเราขึ้นมาใหม่ โดยการกดที่ปุ่ม **`New...`** นั่นเอง (ในตัวอย่างผมสร้างไว้สำหรับ user ผมคนเดียวก็เลยเอาไว้ตรงนี้)

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-M1lfqlFTvI3gmheTI_q%2F-LnIODH8hj74P9Vqc2TB%2Fimage.png?generation=1583529183605819\&alt=media)

ถัดไปก็ทำการตั้งชื่อ variable ของเราได้เลย ซึ่งในตัวอย่างผมจะตั้งชื่อให้ตรงกับใน appsettings.json ละกัน จะได้ใช้เป็นตัวอย่างถัดๆไปต่อ ส่วนค่าที่จะใส่ตรงนี้ก็คือตัว database connection ตัวจริงที่เราจะทำการต่อไปนั่นเอง ตามรูปด้านล่าง แล้วก็กด `OK` เบย

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-M1lfqlFTvI3gmheTI_q%2F-LpOyXIzgLeJHXxFWtia%2Fimage.png?generation=1583529138888085\&alt=media)

เพียงเท่านี้เราก็สามารถเก็บความลับของเราเอาไว้ที่เครื่องได้เรียบร้อยแล้ว ก็กดปุ่ม `OK` อีกครั้งก็เป็นอันเสร็จสิ้นพิธี

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-M1lfqlFTvI3gmheTI_q%2F-LnFObbcQm3I7fKZKJn-%2Fimage.png?generation=1583529170222394\&alt=media)

สุดท้ายเราก็จะลองเรียกตัว api ตัวเดิมดูว่ามันจะอ่านค่าอะไรกลับมาให้เรา ซึ่งเมื่อเราเรียก URL <https://localhost:5001/WeatherForecast/secret> ไปเรียบร้อยเราก็จะได้ตามรูปด้านล่าง

![](https://479516123-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-Lm0_idNbY6k1lwp6hm4%2F-M1lfqlFTvI3gmheTI_q%2F-M-wRxnPY4qqhyHOymV2%2Fimage.png?generation=1583529170488714\&alt=media)

{% hint style="warning" %}
**หมายเหตุ**\
สำหรับใครที่ลองทำตามมาถึงตรงนี้ แล้วมันยังอ่านได้ค่า ABCDEFG แบบเดิมอยู่ ให้ลองปิด Visual Studio หรือ Command Prompt หรือ Terminal ลงไปก่อน แล้วลองเปิดมา Run ตัวเว็บใหม่อีกทีดูนะ
{% endhint %}

{% hint style="success" %}
**ข้อดีในการทำแบบนี้**\
ตัว source code ของเราก็จะไม่มีความลับถูกเขียนไว้ในนั้นอีกต่อไปแล้ว ดังนั้นใน commit history ของเราก็จะลดปัญหาเรื่อง security leak ได้ในระดับหนึ่งเรียบร้อยแล้วนั่นเองขอรับ
{% endhint %}

{% hint style="danger" %}
**ข้อควรระวัง**\
แม้ว่าใน source code จะไม่มีความลับติดไปแล้ว แต่ในตอนทำงานเราก็จะต้องไปบอกทุกคนในทีมให้ทำการกำหนดค่า Environment Variables อยู่ดี และ ทุกคนก็จะรู้รหัสลับต่างๆที่เราพยายามซ่อนอยู่นั่นเอง ดังนั้นคนร้ายก็จะอยู่ในกลุ่มของพวกเรานั่นเอง
{% endhint %}

จากวิธีการแก้ไขปัญหาทั้ง 2 วิธีก็จะช่วยให้โค้ดของเรามีความปลอดภัยเรื่อง security leak เพิ่มขึ้น แต่ก็ยังไม่ใช่ 100% ดังนั้นเดี๋ยวไปดูบทความถัดไปกันดีกว่าว่าจะค่อยๆก่อร่างสร้างตัวยังไง มันถึงจะป้องกันเรื่องพวกนี้บนคลาว์ได้ 99.99%

{% hint style="warning" %}
**หมายเหตุ**\
สาเหตุที่เรียกว่า 99.99% เพราะสุดท้ายระบบก็จะต้องมีใครซักคนหนึ่ง ที่สามารถเข้าไป reset ความลับพวกนี้อยู่ดี เพราะไม่อย่างนั้นดันเผลอไปลบความลับออก หรือดันจำไม่ได้ว่าเก็บไว้ที่ไหน ก็จะทำให้เราไม่สามารถกู้คืนหรือแก้สถานะการณ์อะไรได้เลยนั่นเอง คงไม่อยากเป็นเหมือนบริษัทที่เป็น Bitcoin xchanger ที่เป็นข่าวว่าลืม password จนทำให้ต้องปิดบริษัทเพราะ access ไปดำเนินการต่างๆไม่ได้หรอกชิมิ?
{% endhint %}

{% hint style="success" %}
ชอบ เกลียด โกรธ พบเนื้อหาผิด อ่านแล้ว งง อยากถาม ก็เข้ามาคุยกับ **ดช.แมวน้ำ** ได้ที่ [**Saladpuk Facebook**](https://facebook.com/mr.saladpuk) นะฮ๊าฟ ฝากกดไลค์กดแชร์ด้วยก็ดีนะครับ 😍
{% endhint %}
