Advertisement
  1. Code
  2. C#
Code

ความปลอดภัยใน ASP.NET Web API

by
Difficulty:IntermediateLength:MediumLanguages:

Thai (ภาษาไทย) translation by Phakawan Wongpetanan (you can also view the original English article)

เมื่อคุณได้พัฒนา Web API ก่อนที่คุณจะเปิดเผยไปสู่ลูกค้า  คุณอาจจะต้องการความปลอดภัยในบางส่วนหรือทั้งหมด  ทั้งนี้ขึ้นอยู่กับความต้องการ  ในบทความนี้มีเป้าหมายที่วิธีการยืนยันตัวตน (Authentication) และสิทธิการเข้าถึง (Authorization)

การยืนยันตัวตน (Authentication)

Authentication เป็นกระบวนการพิจารณาว่าบางคนหรือว่าบางสิ่งนั้นคือใคร  ด้วยกระบนการ Authentication เพื่อให้แน่ใจว่าทุกๆ ครั้งที่มีการร้องขอ(request) หรือรับข้อมูล(receive) จาก Web API นั้นได้ส่งมาจากผู้ใช้(client) ด้วยสิทธิที่เหมาะสม

การยืนตัวตัวตนด้วยการใช้ Message Handlers (Authentication Using Message Handlers)

Message hadler เป็นคลาสที่ใช้รับ HTTP request และคืนค่า HTTP response โดยเป็นคลาสที่สืบถอดมาจาก abstract class ชื่อ HttpMessageHandler นี้เป็นสิ่งดีที่จะช่วยให้เราลดความกังวลโดยทำงานในระดับ Http message (level of HTTP message) (ดีกว่าการไปทำระดับ action ใน controller)   message handler สามารถที่จะ

  • อ่านและแก้ไข request header
  • เพิ่ม response header ใน Response
  • ตรวจสอบค่าใน request ก่อนที่จะส่งต่อไปที่คอนโทรลเลอร์ (controller)

ใน Web API  โดยปกติ ชุดของ message handler จะเกี่ยวเนื่องกันไปเป็นลูกโซ่  เราเรียกรูปแบบนี้ว่า delegating handler

HTTP Request flow through Message Handlers

ลำดับของแต่ละ handler ที่เรากำหนดไว้มีความสำคัญเพราะมันจะถูกทำงานแบบตามลำดับ

Hadler ที่สำคัญที่สุดจะอยู่บนสุดเพื่อป้องกันทุกอย่างที่ผ่านเข้ามา  ถ้าตรวจแล้วผ่าน  จะถูกส่งต่อไปยัง delegating handler ที่อยู่ถัดไป  เป็นแบบนี้ไปเรื่อยๆ 

ถ้าที่ผ่านมาทั้งหมดถูกต้องแล้วจะถูกส่งไปยัง API Controller และเรียกใช้งาน Action  อย่างไรก็ตามถ้าการตรวจสอบใดๆ ไม่ผ่าน(fail) (จากเงื่อนไง)ภายใน handler การ request นั้นจะถูกปฏิเสธ (denied) และส่ง response กลับไปยังผู้ใช้(client)

ในบทความนี้เราจะมาเขียนโค้ดสำหรับ handler โดยจะสร้าง 2 handler ดังนี้ 

  1. APIKeyHandler: Handler นี้ทำหน้าที่ในการดัก(inerception) HTTP request และสร้างความมั่นใจว่า header ต้องประกอบไปด้วย API key.
  2. AuthenHandler: Handler นี้ทำหน้าที่ในการตรวจสอบข้อมูลผู้ใช้ (user's credentials) และบทบาท(roles) ของผู้ใช้

การยืนยันตัวตนด้วย API Key (API Key Authentication) 

ในโปรเจค Web API ของคุณ  ให้สร้างโฟลเดอร์ที่ชื่อว่า MessageHandlers และเพิ่ม class ชื่อ APIKeyHandler.cs

APIKeyHandler.cs สืบทอดมาจาก DelegatingHandler ซึ่งสืบทอดมาจาก HttpMessageHandler อีกที.  ในนี้อนุญาตให้แก้ไข(override) ฟังชั่นการตรวจสอบ HTTP request และควบคุมสิ่งที่เราต้องการอนุญาตให้การร้องขอส่งต่อไปยัง handler หรือ controller ถัดไป  หรือหยุดการร้องขอ(request) โดยการส่ง response แบบกำหนดเอง (custom response)

ในคลาสนี้  เรามีเป้าหมายในการทำ overiding เมธอด SendAsync. โดยให้เมธอดนี้มองหา (API_KEY) ใน header ของทุกๆ Http Request และส่งต่อ request ไปยัง Controller เฉพาะ API Key ที่ระบุอย่างถูกต้อง(Valid) มาใน request header เท่านั้น

ก่อนอื่นเราจะต้อง register hadler ก่อน  โดยเข้าไปที่เมธอด Application_Start ในไฟล์ Global.asax

เมื่อเรียก method ผ่าน Web API คุณจะเห็น Bad API Key เป็นข้อความตอบกลับ

สำหรับการสาธิตในบทความนี้ ฉันใช้โครงการและ Url เดียวกันกับที่เคยสร้างไว้ในบทความก่อนหน้านี้เรื่อง "Developing an ASP.NET Web API".

API Key Handler demo

ต่อไปเราจะมาตรวจสอบว่า APIKeyHandler ทำงานได้ถูกต้อง  โดยการสร้าง HTTP Request ด้วย header ที่ถูกบ้าง  เพื่อการนั้นเราจำเป็นต้องสร้าง HTTP header ด้วยค่า ดังนี้

"API_KEY" : "X-some-key"

 ฉันจะใช้ plugin ในบราวเซอร์ Mozilla ที่ชื่อว่า HTTP Tool สำหรับการสร้าง HTTP request header ดังนี้

HTTP Header with HTTP Tool

ในตอนนี้ HTTP request จะถูกส่งต่อค่าทั้งหมดไปที่ controller โดย handler 

ตอนนี้ API key ของเราได้ตรวจสอบอยู่ใน handler แล้ว  เท่านี้เราก็จะมั่นได้ว่าความปลอดภัยของ Web API เราถูกเรียกมาจาก client อย่างถูกต้องด้วย API key ในการเข้าถึงบริการ.  ต่อไปเราจะมาดูว่าเราจะทำการกำหนดความปลอดภัยตามสิทธิของผู้ใช้ได้อย่างไร

พื้นฐานการกำหนดสิทธิการเข้าถึง (Basic Authentication)

Basic authentication เป็นการทำการยืนยันตัวตนของ Http request ที่เรียบงานและเป็นพื้นฐานที่สุด(the most simple and basic)  ผู้ใช้ (client) ส่งค่าเข้ารหัสด้วย Base64 เข้ามาใน Authorize header ในทุก http request และเฉพาะที่ข้อมูลที่ตรวจสอบแล้วเท่านั้น API จึงจะส่งค่าที่ถูกต้องกลับไป Basic authentication ไม่ต้องการการเก็บข้อมูลที่ฝั่งเซิฟเวอร์ (server-side session storage ) หรือการทำงานของ cookies ในทุกๆ request ที่ถูกตรวจสอบโดย API

 เมื่อคุณเข้าใจการ implementation การยืนยันตัวตน (Authentication) ใน Web API แล้วมันง่ายมากที่จะทำ Authentication ในรูปแบบอื่น ๆ กระบวนการตรวจสอบและดัก(hook)อาจะแตกต่างกัน นอกนั้นจะเหมือนๆ กัน

สำหรับการตรวจสอบข้อมูลผู้ใช้ เราสร้างอ๊อฟเจค IPrincipal เพื่อทำหน้าที่เก็บข้อมูลด้านความปลอดภัย

เพิ่มโฟลเดอร์ใหม่ที่ชื่อว่า Security โดยสร้างคลาสใหม่ชื่อ TestAPIPrincipal.cs ในโฟลเดอร์นี้

อ๊อฟเจค IIdentity เกี่ยวเนื่องกับ principal โดยมี property ที่ชื่อว่า IsAuthenicated  ถ้าผู้ใช้ได้ทำการ authenticate มาแล้ว property นี้จะให้ค่าเป็นจริง (return true) ถ้าไม่ได้จะให้ค่าเป็นเท็จ (return false)

ถึงตอนนี้เราจะมาสร้าง handler อีกอันนึงชื่อว่า AuthHandler.cs

ในคลาสนี้จะประกอบไปด้วย private method ที่ชื่อ ValidateCredentials ซึ่งทำหน้าที่ถอดรหัส (decode) ค่าของ username และ password จาก Header ของ HTTP request และยังมี SendAsync method สำหรับขัดขวาง HTTP request

ถ้า credential ของผู้ใช้(client) ถูกต้องแล้ว IPrincipal จะแนบ(attache) ไปยัง Thread ปัจจุบัน  เช่น Thread.CurrentPrincipal นอกจากนี้เรายังตั้งค่า HttpContext.Current.User เพื่อให้บริบทความปลอดภัยที่สอดคล้องกัน และอนุญาตให้เราเข้าถึงรายละเอียดของผู้ใช้ปัจจุบันจากที่ใดก็ได้ในโปรแกรม

เมื่อ request ผ่านการยืนยันตัวตน(Authenticate) แล้ว base.SendAsync จะถูกเรียกเพื่อส่่ง request เข้าไปภายใน handler ถ้า response มี Http unauthorized header โค้ดจะทำการแทรก(inject)  WwwAuthenticate ด้วยค่า Basic เพื่อที่จะบอก client ว่า service ของเราต้องการ basic authentication

ตอนนี้ เราจะต้อง register handler นี้ใน Global.Asax คลาสเหมือนกับที่เราทำ ApiKeyHandler.  โปรดทำให้แน่ใจว่า AuthHandler นี้อยู่ด้านล่าง handler แรกที่เรา register จะได้มั่นใจว่าเรียงลำดับได้อย่างถูกต้อง

ก่อนที่เราจะไปดูเรื่องพื้นฐานการยืนยันตัวตน (basic authentication) ใน action เราจะต้องทำการ implement สิทธิการเข้าถึง (authorization)

สิทธิการเข้าถึง (Authorization)

การยืนยันตัวตน(Authorization) จะตรวจสอบว่า ผู้ใช้ที่ยืนยันตัวตนแล้วสามารถทำการดำเนินการเพียงบางส่วนของ action หรือใช้งานทรัพยากร(resource)บางส่วนwfh  กระบวนการนี้ในเว็บ API ที่เกิดขึ้นใน pipeline หลังจาก
ยืนยันตัวตน(Autentication) และอยู่ก่อนที่ action ใน controller จะถูกเรียกใช้ (execute)

การใช้งานแอตทริบิว Authorize 

ASP.NET MVC Web API ได้ให้ authorization filter ที่ชื่อว่า AuthorizeAttribute มาให้ซึ่งใช้จะตรวจสอบ request IPrincipal โดยตรวจสอบ property ที่ชื่อ Identity.IsAuthenticated และส่งค่า(return) HTTP staus เป็น 401 Unauthorized ถ้ามีค่าเป็นเท็จ และ action ที่เรียกมาจะไม่ถูกเรียกใช้.  filter นี้สามารถใช้ได้ในระดับต่าง ๆ ได้ด้วย  เช่น ในระดับ controller หรือ action  และสามารถง่ายๆ ด้วยการใส่ [Authorize] ไว้บน controller หรือ action

เมื่อแอตทิบิวนี้ถูกประกาศไว้จะช่วยป้องกัน action ทั้งหมดใน contoller นี้ให้ไม่สามารถเรียกใช้โดยผู้ใช้ที่ยังไม่ผ่านการยืนยันตัวตน

เมื่อยืนยันตัวนแล้ว hanler จะเข้าไปตั้งค่า(set) IPrincipal ของผู้ใช้ปัจจุบัน  ก่อนที่ request นี้จะถูกส่งไปยัง controller.  AuthorizeAttribute จะตรวจสอบการเข้าถึง controller/action เฉพาะสำหรับผู้ใช้ปัจจุบัน

มาดู action นี้มัน  ก่อนอื่นเราจะมาสร้าง HTTP request ที่ไม่มี credentials 

Access denied for unauthorized users

การเข้าถึงนี้จะถูกปฎิเสธโดย AuthorizeAttribute

ตอนนี้เราจะมาสร้าง request อีกอันนึงโดยกำหนด Authorization header ดังนี้

Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=

ค่า dXNlcm5hbWU6cGFzc3dvcmQ= เป็นค่าที่เกิดจากเข้ารหัสของ username:password (ผู้แปล: เป็นการเอา string มาต่อกัน)

คำขอนี้ได้รับสิทธิการเข้าถึงการควบคุม/การดำเนินการตามที่คาดไว้ (ทำงานได้ถูกต้องตามที่คาดไว้)

Access granted for user with proper credentials

นี่คือตัวอย่างของการความปลอดภัยของ action สาธารณะ (public action)

การกำหนดสิทธิ์ในระดับ Action (Action Level Authorization)

นอกจากนี้เรายังสามารถกำจัดสิทธิเป็นบางส่วนของ action ด้วยการเพิ่มแอททริบิว [Authorize] ที่ action. การทำแบบนี้ทำให้เราสามารถอนุญาตให้มีทั้งการป้องกัน (protect)  และไม่ป้องกัน (unprotect) action ที่อยู่ใน controller เดียวกันได้

แอททริบิว [AllowAnonymous] 

อีกทางหนึ่งที่จะสามารถทำทั้งป้องกัน (protected) และไม่ป้องกัน (unprotect) action ภายใน controller ด้วยการใช้แอททริบิว [AllowAnonymous].  เมื่อเรากำหนดแอททริบิว [Authorize] ในระดับ controller และกำหนดแอททริบิว [AllowAnonymous] ใน action ใดภายใน controller แล้ว Action นั้นจะข้ามการทำงานของแอททริบิว [Authorize] ไป

การตรวจสอบบทบาท (Role) และผู้ใช้ (User)

เราสามารถที่จะกรอง(filter) เฉพาะบทบาท (role) และผู้ใช้ (user) ในการเข้าถึงได้เหมือนกัน  ยกตัวอย่างเช่น  เราสามารถใส่ [Authorize(Roles = "Admin")] ไว้ใน controller และ action เพื่อกำหนดสิทธิได้

การทำแอททริบิวแบบกำหนดเอง (Custom Authorization Attribute)

เราสามารถสร้างแอททริบิวแบบกำหนดเอง (custom attribute) ได้ขึ้นกับความต้องการของเรา. ทางนึงที่เราสามารถทำได้ถือคือการขยาย (extending) AuthorizeAttribute

ถ้าเราต้องการจำกัดบริการของเราเว็บ API ถึงเพียงบางพื้นของโลก โดยจำกัดการเข้าถึงผู้ใช้ที่ไม่ได้อยู่ภายในอยู่ช่วง IP ที่เราต้องการ เราสามารถสร้างแอตทริบิวต์แบบกำหนดเอง(Custom attibute) โดยกำหนดภายในคลาส AuthorizeAttribute และ overriding เมธอดที่ชื่อ IsAuthorized

เมื่อเรามีแอตทริบิวต์ Authorize ของเราเองเราสามารถกำหนดการทำงานของ controller/action ไว้ข้างในได้ 

บทสรุป

ในบทความนี้  เราได้ดูว่าทำยังไง ASP.NET Web API เราจึงจะปลอดภัยก่อนที่จะเปิดให้ใช้งานจากภายนอก เราได้ดูว่าทำอย่างไรจึงจะยืนยันตัวตน (authenticate) Http request ว่ามี API key และข้อมูลผู้ใช้ (user credentials) ถูกต้องหรือไม่.  ด้วยความรู้ที่อยู่ในมือของเรา ฉันเชื่อว่าเราพร้อมที่จะพัฒนาด้านความปลอดภัยใดๆ ก็ได้ใน API ของเรา

สำหรับพวกคุณใครที่เพิ่งเริ่มต้นการใช้งาน Laravel หรือกำลังมองหาความรู้เพิ่มเติม,เว็บไซต์,หรือส่วนขยายสำหรับแอพลิเคชั่น  เรามีหลากหลายสิ่งให้คุณศึกษาใน Envato Marget

ฉันหวังว่าคุณจะสนุกกับการเรียนรู้จากบทความนี้  และอย่าลืมทิ้งคำถามหรือคอมเม้นท์ข้างล่างนี้ด้วยละ!

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.