Security
น้องๆ เคยเจอไหม เว็บไซต์ที่เราเข้าประจำ จู่ๆ ก็มีโฆษณาแปลกๆ เด้งขึ้นมา หรือโดน redirect ไปหน้าเว็บที่ไม่รู้จัก? บางทีอาจจะเป็นเพราะเว็บนั้นโดน Hack หรือโดนแทรกสคริปต์อันตรายเข้าไปก็ได้นะ
Web Security Headers เนี่ย เปรียบเสมือนเกราะป้องกันภัยให้เว็บไซต์ของเราอีกชั้นหนึ่ง โดยเฉพาะ CSP (Content Security Policy) คือพระเอกของเราในวันนี้ มันจะช่วยกำหนดว่า Browser สามารถโหลด Content อะไรจากที่ไหนได้บ้าง เช่น รูปภาพ โค้ด JavaScript หรือ CSS เพื่อป้องกัน XSS (Cross-Site Scripting) Attacks ซึ่งเป็นภัยร้ายอันดับต้นๆ ของเว็บเลย
สมัยผมทำร้านเน็ตฯ เนี่ย เจอลูกค้าโดน Hack Facebook กันบ่อยมาก ส่วนใหญ่ก็มาจากการคลิกลิงก์แปลกๆ ที่เพื่อนส่งมาให้ พอมาทำเว็บเอง เลยให้ความสำคัญกับเรื่อง Security เป็นพิเศษ เพราะถ้าเว็บโดน Hack ลูกค้าเสียความเชื่อมั่น แถม Google ยังแบนอีกต่างหาก
CSP คือ HTTP Response Header ที่บอก Browser ว่าอนุญาตให้โหลด Resource อะไรจาก Source ไหนได้บ้าง Source ก็คือ URL นั่นแหละ เช่น อนุญาตให้โหลดรูปภาพจาก domain ของเราเอง หรืออนุญาตให้โหลด JavaScript จาก CDN ที่เราไว้ใจได้
XSS คือการที่ Hacker แทรกสคริปต์อันตรายเข้าไปในเว็บไซต์ของเรา แล้ว Browser ของผู้ใช้ก็จะ execute สคริปต์นั้น ทำให้ Hacker สามารถขโมยข้อมูล หรือ redirect ผู้ใช้ไปยังเว็บไซต์อื่นได้ XSS มีหลายรูปแบบ แต่ CSP สามารถช่วยป้องกันได้หลายรูปแบบเลย
Directives คือส่วนประกอบของ CSP ที่ใช้กำหนด Policy ต่างๆ เช่น default-src, script-src, img-src, style-src แต่ละ Directive จะควบคุมการโหลด Resource แต่ละประเภท ตัวอย่างเช่น script-src 'self' cdn.example.com หมายความว่าอนุญาตให้โหลด JavaScript จาก domain ของตัวเอง และจาก cdn.example.com เท่านั้น
การใช้งาน CSP ไม่ยากอย่างที่คิด เริ่มจากเราต้องกำหนด HTTP Response Header ก่อน แล้วค่อยๆ ปรับแต่ง Policy ให้เหมาะสมกับเว็บไซต์ของเรา
เราสามารถกำหนด HTTP Response Header ได้หลายวิธี ขึ้นอยู่กับ Web Server ที่เราใช้ เช่น Apache, Nginx หรือ IIS สมัยผมใช้ Apache บ่อยสุดๆ เพราะ Config ง่ายดี
ตัวอย่างการกำหนด CSP Header ใน Apache:
<IfModule mod_headers.c>
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' https://code.jquery.com; img-src 'self' data:; style-src 'self' 'unsafe-inline';"
</IfModule>
Code snippet ด้านบน อนุญาตให้โหลด JavaScript จาก jQuery CDN ได้ด้วย และอนุญาตให้ใช้ Inline Style ได้ ('unsafe-inline') แต่แนะนำว่าหลีกเลี่ยงการใช้ Inline Style จะดีกว่านะ เพื่อความปลอดภัย
หลังจากกำหนด CSP Header แล้ว ให้ลองเข้าเว็บไซต์ของเรา แล้วเปิด Developer Tools ใน Browser (กด F12) ดูที่ Console Tab ถ้ามี Error เกี่ยวกับ CSP แสดงว่า Policy ของเรายังไม่ถูกต้อง ให้ค่อยๆ ปรับแก้ Policy ทีละนิด จนกว่าจะไม่มี Error แสดง
สมัยก่อน ผมเคยเจอเคสที่ CSP บล็อก Google Analytics เพราะลืมใส่ Domain ของ Google Analytics ใน script-src กว่าจะแก้ได้ เล่นเอาเหงื่อตกเลย เพราะข้อมูล Analytics สำคัญมาก
อย่าลืมเข้าไปอ่านบทความอื่นๆ ที่ SiamCafe Blog ด้วยนะ มีเรื่อง IT สนุกๆ อีกเยอะเลย
CSP ไม่ใช่ Security Header ตัวเดียวที่เราควรใช้ ยังมี Header อื่นๆ ที่ช่วยเสริมความปลอดภัยให้เว็บไซต์ของเราได้อีก เช่น
ตารางเปรียบเทียบ CSP กับ Header อื่นๆ:
| Header | หน้าที่ | ข้อดี | ข้อเสีย |
|---|---|---|---|
| Content-Security-Policy (CSP) | ควบคุม Resource ที่ Browser สามารถโหลดได้ | ป้องกัน XSS ได้ดี, ปรับแต่งได้ละเอียด | Config ค่อนข้างซับซ้อน |
| X-Frame-Options | ป้องกัน Clickjacking Attacks | ใช้งานง่าย | ป้องกันได้แค่ Clickjacking |
| Strict-Transport-Security (HSTS) | บังคับให้ Browser ใช้ HTTPS | เพิ่มความปลอดภัยในการรับส่งข้อมูล | ต้องใช้งาน HTTPS ก่อน |
สรุปคือ CSP เป็นเครื่องมือที่ทรงพลังในการป้องกัน XSS แต่ต้องใช้งานอย่างระมัดระวัง และควรใช้ร่วมกับ Security Headers อื่นๆ เพื่อให้เว็บไซต์ของเราปลอดภัยยิ่งขึ้น ลองเข้าไปอ่านบทความอื่นๆ ที่ SiamCafe Blog ดูนะ เผื่อเจอเทคนิคใหม่ๆ ที่เป็นประโยชน์
CSP นี่เหมือนเกราะป้องกันเว็บเราอีกชั้นนึงเลยนะน้อง แต่จะตั้งค่าให้ดีนี่ต้องอาศัยความเข้าใจพอสมควรเลย สมัยผมทำร้านเน็ตนี่ก็เคยโดน Hack เว็บไซต์เหมือนกัน (ไม่ใช่เว็บร้านเกมนะ 555+) เลยเข้าใจเลยว่าเรื่อง Security นี่สำคัญขนาดไหน
จำไว้ว่า "Less is More" เริ่มจาก policy ที่เข้มงวดน้อยที่สุดก่อน แล้วค่อยๆ เพิ่มเติมไปเรื่อยๆ อย่าเพิ่งใส่จัดเต็มตั้งแต่แรก ไม่งั้นเว็บพังแน่นอน
อันนี้สำคัญมาก! ก่อนจะบังคับใช้ CSP จริงจัง ให้ลองใช้ Content-Security-Policy-Report-Only ก่อน แล้วส่ง report ไปที่ endpoint ที่เรากำหนดไว้
Content-Security-Policy-Report-Only: default-src 'self'; report-uri /csp-report-endpoint;
วิธีนี้จะช่วยให้เราเห็นว่า policy ที่เราตั้งไว้มัน "บล็อค" อะไรบ้าง โดยที่เว็บเรายังใช้งานได้ปกติ เราจะได้ปรับแก้ให้ถูกต้องก่อนที่จะ "บังคับใช้" จริง
Inline script หรือ style นี่ตัวดีเลย CSP จะบล็อคหมดถ้าเราไม่บอกว่า "อนุญาต" ให้รันได้ วิธีที่แนะนำคือการใช้ nonce หรือ hash
Nonce: สร้าง random string ทุกครั้งที่โหลดหน้าเว็บ แล้วใส่ใน script tag และ CSP header
<script nonce="R4nd0mN0nc3">
// Your inline script
</script>
Content-Security-Policy: default-src 'self'; script-src 'nonce-R4nd0mN0nc3';
Hash: คำนวณ hash ของ script หรือ style แล้วใส่ใน CSP header
<script>
// Your inline script
</script>
Content-Security-Policy: default-src 'self'; script-src 'sha256-SOME_HASH_VALUE';
เลือกใช้วิธีไหนก็ได้ที่สะดวก แต่ Nonce จะปลอดภัยกว่าเพราะเปลี่ยนทุกครั้ง
Wildcard (*) นี่ใช้ได้นะ แต่ต้องระวัง! เพราะมันจะอนุญาตทุกอย่างที่อยู่ใน domain นั้นๆ ถ้า domain นั้นโดน Hack ก็ซวยเลย
พยายามระบุ domain ให้ชัดเจนที่สุดเท่าที่จะทำได้ เช่น แทนที่จะใช้ img-src *.example.com ให้ใช้ img-src img1.example.com img2.example.com แทน
โลกมันเปลี่ยนไปทุกวัน Hackers ก็หาวิธีใหม่ๆ มา Hack เว็บเราตลอดเวลา ดังนั้นเราต้อง monitor CSP report อย่างสม่ำเสมอ แล้วปรับปรุง policy ให้ทันสมัยอยู่เสมอ
นอกจากนี้ library หรือ Framework ที่เราใช้อาจมีการเปลี่ยนแปลงที่ส่งผลต่อ CSP ดังนั้นต้องคอย update policy ตามไปด้วย
ต้องเพิ่ม script-src 'self' www.google-analytics.com ajax.googleapis.com; และ img-src 'self' www.google-analytics.com; ใน CSP header
ต้องเพิ่ม font-src 'self' data: maxcdn.bootstrapcdn.com; และ style-src 'self' maxcdn.bootstrapcdn.com; ใน CSP header (ถ้าใช้ CDN)
ต้องเพิ่ม frame-src 'self' www.youtube.com; ใน CSP header
ได้! มี Plugin ให้ใช้เยอะแยะเลย ลองหาดูใน WordPress Plugin Directory แต่ต้องระวังเรื่อง Compatibility กับ Plugin อื่นๆ ด้วย
CSP นี่เป็น Security Header ที่สำคัญมาก แต่ต้องตั้งค่าให้ถูกต้องถึงจะได้ผล ถ้าตั้งผิดก็อาจจะทำให้เว็บพังได้ เริ่มจาก Report-Only Mode, ใช้ Nonce/Hash สำหรับ Inline Scripts/Styles, ระวัง Wildcard, และ Monitor Policy อย่างสม่ำเสมอ
Security นี่เป็นเรื่องที่ไม่จบไม่สิ้น ต้องคอยเรียนรู้และปรับปรุงอยู่เสมอ สมัยผมทำร้านเน็ตก็เจ็บมาเยอะ ถึงได้เข้าใจว่า "กันไว้ดีกว่าแก้" จริงๆ
ใครสนใจเรื่อง Forex ลองดูที่ iCafeForex นะครับ เผื่อจะรวยไม่รู้เรื่อง 555+
และอย่าลืมติดตาม SiamCafe Blog นะครับ มีบทความดีๆ อีกเยอะเลย