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

🤔 การเก็บรหัสลับบนคลาว์ เขาทำกันยังไงนะ ?

😢 ปัญหา

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

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

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

ข้ามไปอ่านหัวข้อถัดไปได้เลยถ้าใครใช้ asp.net core api เป็นอยู่แล้ว

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

ASP.NET Core

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

dotnet new api -n saladpuk-demo

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

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

dotnet run

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

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

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

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

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 แทนตามโค้ดด้านล่าง

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

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

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

public class WeatherForecastController : ControllerBase
{
    private readonly IConfiguration configuration;

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

    ...
}

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

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

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

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

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

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

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

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

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

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

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

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

Last updated

Was this helpful?