ลงลึกกับ OAuth กันดีกว่า

จากที่เล่าเรื่อง OAuth กับ OIDC ว่ามีหน้าที่ในการทำอะไรไปแล้ว ใน Blog ก่อนหน้า รู้จัก OAuth 2.0 กันก่อน บทความนี้จะลงในรายละเอียด ที่อาจจะทำให้หนักหัวกับหลายๆคน แต่อาจจะเป็นเรื่องง่ายๆสำหรับอีกหลายๆคนขึ้นอยู่กับมีประสบการณ์กับมันมากแค่ไหน แต่ยังไงจะพยายามอธิบายให้เข้าใจได้แบบง่ายที่สุดเท่าที่จะทำได้นะครับ – -”

ก่อนอื่น อยากให้ลองมองย้อนกลับไปยุคก่อนที่จะมี OAuth / OIDC มาให้ใช้งานกันแบบทุกวันนี้ เรามีการบริหารจัดการ Authentication กันอย่างไร

จากภาพด้านบน จะแสดงการล็อคอินเว๊ปแอพพลิเคชั่นช่วงแรกๆ (ก่อนมี OAuth/OIDC) คือ ผู้ใช้งานจะทำการป้อน User / Password ผ่านเวปฟอร์มแล้วกด Submit, ฟอร์มจะส่ง User / Password ไปทำการตรวจสอบผ่านแอพพลิเคชั่นและดาต้าเบส ตามขั้นตอนดังนี้

  • ค้นหา User  และเอา password ไปทำการ Hash (หรือเอา Password ไปต่อกับ Salt ก่อนแล้วค่อย Hash)
  • เปรียบเทียบ Hash ที่ได้กับ Hash ที่มีใน DB
  • ตรวจสอบ User information
  • ตรวจสอบ Authorize / Role ของ User นั้นๆ เพื่อนำมาแสดงผล
  • กำหนด SessionID และอายุของ Session ผ่าน Cookie เพื่อเข้าใช้งานระบบ

จากขั้นตอนข้างต้นเป็นกระบวนการ Login ที่มีมานาน และหลายๆคนก็ใช้วิธีนี้มาก่อนในการพัฒนา Application แต่วิธีการในการบริหารจัดการ User / Password ลักษณะนี้อาจส่งผลให้เกิดความลำบากในการดูแลความปลอดภัย และการดูแลรักษาระบบในอนาคต ตัวอย่างเช่น

  • User / Password ของแต่ละ Application แยกจากกัน ยากในการทำ Single Sign On (SSO)
  • เมื่อมีการเปลี่ยนไปของ Security Standard หรือ Security Requirements ในการดูแล User / Password เช่น ต้องการเปลี่ยน Hash Algorithm หรือเพิ่มความปลอดภัยในการ Authentication นอกเหนือไปจากการ Hash ในอนาคต
  • Compliance ต่างๆ ที่เกี่ยวข้องกับการดูแลข้อมูลผู้ใช้งาน

ดังนั้น OAuth / OIDC เริ่มเข้ามามีบทบาทในการเป็น “Best Practice” เพื่อช่วยแก้ปัญหาดังกล่าวนั่นเอง!

อย่างที่ทุกท่านทราบ OAuth เป็น Authorization Framework ที่ช่วยในการ Delegated Authorization ไปยัง Application ต่างๆ ดังเช่นตัวอย่างด้านล่าง ผู้ใช้งานเชื่อถือ Gmail และ TAMA โดยต้องการให้ TAMA Application เข้าถึง Contact จาก Gmail ของเขาได้ จากหน้า Web ที่เราเห็นทั่วๆไป เราคงจะเคยเห็นปุ่ม “Login with Google” หรือ “Login with Facebook” ซึ่งเมื่อกด เราจะสามารถเข้าถึงข้อมูลของเราใน Google และ Facebook และส่งผ่านไปยัง Client Application ที่ต้องการใช้งานข้อมูลดังกล่าวได้  

โดยจะขอแสดงโฟลการทำงานอย่างคร่าวๆของ OAuth ว่า OAuth เข้ามาแก้ปัญหาดังกล่าวได้อย่างไร ก่อนที่จะลงรายละเอียดลึกลงไปนะครับ

จากสถานการณ์ข้างต้น จะขออธิบายโฟลการทำงานเพิ่มเสริมความเข้าใจ โดยที่จะยังไม่มี Parameter ต่างๆ ที่รับส่งกันในแต่ละ Step ดังนี้ครับ

  1. ผู้ใช้งานกด ปุ่ม “Connect with Gmail” จากนั้น Browser ของผู้ใช้งาน (Frontend) จะ Redirect การทำงานไปยัง Gmail ที่ URL account.google.com
  2. account.google.com จะ prompt ให้ผู้ใช้งานพิมพ์ User / Password ของ Gmail ผ่านทาง account.google.com โดยตรง เพื่อตรวจสอบ User / Password เมื่อ login ผ่าน account.google.com สำเร็จ จะแสดง prompt ถาม ว่า TAMA ต้องการเข้าถึง Public Profile และ Contact ผู้ใช้งานจะยินยอมหรือไม่?
  3. เมื่อผู้ใช้งานกด “Yes” เพื่อยอมรับ Browser (Frontend) จะทำการ Redirect ผู้ใช้งานกลับไปยัง URI ที่กำหนดไว้ที่ฝั่ง TAMA (tama.co/callback) ซึ่งเรียกว่า Callback URI หรือ Redirect URI
  4. จากนั้น Server ของ TAMA จะทำการเชื่อมต่อไปยัง API ของ Google (เป็นเส้นประ) คือ Google Contact API เพื่อทำการร้องขอ Public Profile และ Contact จาก Gmail กลับมายัง TAMA เพื่อแสดงผลการ Login บน TAMA เป็นอันจบโฟลการทำงาน

จากโฟลการทำงานข้างต้นเชื่อว่าทุกท่านน่าจะเห็นแนวทางการทำงานของ Delegated Authorization โดยใช้ OAuth ในแบบ Overview ว่ามี Component อะไรที่เกี่ยวข้องบ้าง และ Redirect กันไปมาอย่างไร ก่อนที่จะลงไปในรายละเอียดที่ลึกขึ้นว่ามี Parameter อะไรบ้าง จะมีคำศัพท์ที่ต้องเข้าใจตรงกันก่อน

คำศัพท์ต่างๆของ OAuth 2.0 

  • Resource Owner – เจ้าของ Resource ก็คือ “คน” ที่เป็นเจ้าของข้อมูล และกดปุ่ม “ยอมรับ” หรือ “ไม่ยอมรับ”
  • Client – Application ปลายทางที่ต้องการเข้าถึง Resource จากตัวอย่างคือ TAMA Application
  • Authorization Server – ระบบที่สามารถจะตอบได้ว่า “Yes” ฉันจะให้เข้าถึง Resource อะไรบ้าง (จากตัวอย่างคือ account.google.com ที่ตรวจสอบผู้ใช้งาน และผู้ใช้งานกด “Yes”
  • Resource Server – ระบบที่เก็บข้อมูลที่ Client Application ต้องการใช้งาน จากตัวอย่างจะเป็น Google Contact API ที่เก็บ Public Profile และ Contact
  • Authorization Grant – โฟลวิ่งไปมาระหว่าง Authorization Server และ Client เพื่อ Proof ว่าผู้ใช้งาน (Resource Owner) ได้ทำการกด Yes เรียบร้อยแล้ว เพื่อยืนยันในระบบว่าสิทธิที่จะเข้าถึง Resource ได้
  • Redirect URI – เป็น URI ที่กำหนด ไว้ล่วงหน้าเพื่อให้ Authorization Server ทำการ Redirect กลับไปที่ Client Application บางครั้งเรียกว่า Callback URI จากตัวอย่างคือ tama.co/callback
  • Access Token – นี่คือสิ่งที่ Client Application ต้องการจริงๆ เพราะ Access Token เป็นเหมือน “ตั๋ว” ที่จะทำให้ Client Application สามารถเข้าถึง Resource ต่างๆ ตามที่กำหนดบน Resource Server ได้ จากตัวอย่างจะเห็นว่า Client จะสามารถเข้าถึง Public Profile และ Contact ได้ตามที่กำหนด แน่นอนมันต้องใช้ Access Token นี่ละเป็นตั๋วในการเข้าถึงมัน

** บางครั้ง Authorization Server และ Resource Server จะเป็น Component เดียวกัน ขึ้นอยู่กับระบบงาน

หลังจากรู้จักศัพท์แสงต่างๆ แล้ว เรากลับมาที่โฟลเดิมแต่จะเติมรายละเอียดของ Parameter บางส่วนของ “OAuth Authoriztion Code Flow” เข้าไปนะครับ

จากภาพจะเพิ่มคำศัพท์ต่างๆของ OAuth ลงไปในแต่ละ Components และเพิ่ม Parameter รวมถึงโฟลบางอย่างตาม Authorization Code เข้าไปดังนี้ครับ

  1. ผู้ใช้งาน (Resource Owner) กด ปุ่ม “Connect with Gmail” จากนั้น Browser ของผู้ใช้งาน (Frontend) จะ Redirect การทำงานไปยัง Gmail ที่ URL account.google.com (Authorization Server) โดยส่ง Configuration บางอย่างไปให้กับ Authorization Server ด้วย เช่น หากการทำงานทุกอย่างสมบูรณ์ ให้ Authorization Server ทำการ Redirect กลับไปยัง URL tamacorp.co/callback และ Type of Authorization แบบไหนที่ Client ต้องการใช้งาน โดยจากตัวอย่างจะเป็น code (Authorization Code) ซึ่งจริงๆแล้วจะมีหลายแบบ โดยจะอธิบายต่อไปครับ
  2. account.google.com (Authorization Server) จะ prompt ให้ผู้ใช้งานพิมพ์ User / Password ของ Gmail ผ่านทาง account.google.com โดยตรง เพื่อตรวจสอบ User / Password เมื่อ login ผ่าน account.google.com (Authorization Server) สำเร็จ จะแสดง prompt ถาม ว่า TAMA ต้องการเข้าถึง Public Profile และ Contact ผู้ใช้งานจะยินยอมหรือไม่?
  3. เมื่อผู้ใช้งานกด “Yes” เพื่อยอมรับ Browser (Frontend) จะทำการ Redirect ผู้ใช้งานกลับไปยัง CallBack URI ที่กำหนดไว้ที่ฝั่ง TAMA (tama.co/callback) พร้อมด้วย Authorization Code ที่ Grant จาก Authorization Server
  4. Backend ของ Client Application จะได้รับ Authorization Code กลับมาจากขั้นตอนก่อนหน้า จะส่ง Authorization Code นั้นกลับไปยัง Authorization Server เพื่อบอกว่า “เฮ้! คุณพึ่งส่ง Authorization Code มาให้ฉัน จะขอแลก Authorization Code นี้กับ Access Token เพื่อเข้าถึง Resource ได้ไหม?” จากนั้น Authorization Server จะตรวจสอบว่า Authorization Code นั้นยัง Valid อยู่ไหม หมดอายุไปหรือยัง ซึ่งหากตรวจสอบทุกอย่างถูกต้องจะส่ง Access Token กลับไปให้กับ Client เพื่อใช้งาน

    * ขั้นตอนนี้ทำเพื่ออะไร? สงสัยไหมว่าทำไมต้องแลกไปแลกมาหลายรอบให้วุ่นวาย จริงๆ Authorization Server ส่ง Access Token ไปแต่แรกก็จบแล้ว

    พูดแบบนั้นก็ถูกครับ แต่ลองมองดูดีๆการทำงานของขั้นตอนนี้ เกิดขึ้นระหว่าง Backend ของ Client Application กับ Authorization Server ซึ่งช่วยเพิ่มความปลอดภัยและน่าเชื่อถือให้กับระบบอีกขั้น เพราะเราไม่ควรเชื่อถือสิ่งที่ส่งมาจาก Browser ทั้งหมด ดังนั้นเราควรจะตรวจสอบข้อมูลที่รับมาเพิ่มเติม โดยใช้ Backend ด้วย ซึ่งจะช่วยให้ระบบมีความปลอดภัยและมีความน่าเชื่อถือสูงขึ้น ออ ไหนๆมาขนาดนี้ละ จะมีคำศัพท์แถมไปอีกหน่อย ดังนี้

    1. Back Channel (Highly Secure Channel) – OAuth จะมองว่าการส่ง API Request โดยตรงจาก Client Backend ผ่าน HTTPS ไปยัง Authorization Server มีความปลอดภัยที่สูงกว่า
    2. Front Channel (Less Secure Channel) – การ Request API ผ่าน Browser หรือ Frontend ผ่าน HTTPS ไปยัง Authorization Server จะมีความปลอดภัยต่ำกว่า การ Run จาก Server ของเรา ไม่ได้แปลว่า Browser ไม่ Secure นะครับ แต่ยังไงก็ Secure น้อยกว่าเรียกผ่าน Backend แน่ๆ และเราไม่ควร Trust ทุกอย่างจาก Browser ควรจะต้องมีการ Verify ถ้าทำได้หากย้อนไปดูที่โฟลดีๆจะเห็นว่ามีทั้งเส้นประและเส้นทึบ โดย เส้นประหมายถึง Back Channel และเส้นทึบคือ Front Channel บางงานต้องทำผ่าน Front Channel บางงานทำผ่าน Back Channel เพื่อให้แน่ใจว่าทั้งโฟลมีความปลอดภัยสูงสุด เช่น การแลกเปลี่ยน Authorization Code กับ Access Token ทำไมจะต้องทำผ่าน Back Channel?อยากให้ลองนึกภาพว่าทุกอย่างทำผ่าน Front Channel หากเครื่อง Client ติด Thojan หรือผู้ไม่หวังดี Intercept Authorization Code ไปได้ และเอาไปทำการแลกเปลี่ยนกับ Access Token…. จบ! ข้อมูลทุกอย่างของผู้ใช้งานจะไหลไปหาผู้ไม่ประสงค์ดีทันที ดังนั้น OAuth จึงกำหนดให้การแลกเปลี่ยน Authorization Code กับ Access Token ทำผ่าน Back Channel ที่มีการ Pre-Define ค่า Secret Key เอาไว้ที่ Client Backend เท่านั้น (ซึ่ง Client ไม่รู้) ดังนั้นจึงเป็นการ Authenticate Request ระหว่าง Server อีกรอบนึง ซึ่งจะช่วยให้ระบบมีความปลอดภัยสูงขึ้นอีกระดับเลย 🙂 
  5. เมื่อ Client ได้รับ Access Token จาก Authorization Server แล้ว จากนั้น TAMA (Client) จะทำการเชื่อมต่อไปยัง API ของ Google คือ Google Contact API (Resource Server) เพื่อทำการร้องขอ Public Profile และ Contact จาก Gmail กลับมายัง TAMA โดย Resource Server ก็จะทำการตรวจสอบเพิ่มเติมว่า Access Token นั้น มีสิทธิเข้าถึง Resource อะไรบ้าง ไม่ใช่ว่าจะสามารถเข้าถึงได้ทุกสิ่งอย่างบน Resource Server จากตัวอย่าง จะสามารถเข้าถึงได้เฉพาะ Public Profile และ Contact ก็จะทำการส่งข้อมูลดังกล่าวกลับไปยัง Client ตามที่ร้องขอ เพื่อแสดงผลการ Login บน TAMA เป็นอันจบโฟลการทำงาน

จากโฟลการทำงานของ OAuth แบบ Authorization Code ผมเชื่อว่าทุกท่านจะเริ่มเห็นภาพและเข้าใจศัพท์แสงที่แสน “งง” ของมันมากขึ้นไม่มากก็น้อย เอาจริงๆ ผมก็งงกะมันมาก่อน เลยอยากให้ทุกคนเข้าใจมันมากกว่าแค่ Ok มันคือ OAuth / OIDC หรือมี SDK ไหม หรือหา Lib จากเนตมา Configure กันมั่วซั่วโดยที่ไม่รู้ว่ามันทำๆไม และทำงานยังไง อันนั้นจะปวดหัวกว่าในภายหลัง 🙂

จากนี้เราจะมาดูกันต่อว่า การกำหนดการเข้าถึง Resource ที่กำหนดได้เท่านั้น ทำได้อย่างไร โดยจากตัวอย่างที่แล้ว เรากำหนดให้ Client ทำการเข้าถึง Public Information และ Contact ได้เท่านั้น ไม่สามารถแก้ไข หรือลบ Contact ได้ การทำลักษณะนี้ทำให้เราสามารถกำหนด Permission แบบละเอียดๆเป็นราย Resource ได้ ไม่ใช่แค่เข้าถึงได้ทั้งหมดกับเข้าถึงไม่ได้เลย โดยสิ่งที่เป็นตัวกำหนด จะมีศัพท์เพิ่มขึ้นมา คือ

  • Scope
  • Consent

Scope วิธีการทำงานคือ Authorization Server จะ List Scope ที่มีขึ้นมา เช่น Contact.Read, Contact.Write, E-Mail.Read, E-Mail.Write เป็นต้น ในส่วนของ Client จากตัวอย่างใน Blog ที่ผ่านมา Client จะไม่สนใจว่า Server มี Scope อะไรบ้าง จะสนใจแค่ Scope ที่ตัวเองต้องการคือ Contact.Read  เท่านั้น ซึ่งหาก Client ต้องการมากกว่านั้นก็สามารถร้องขอหลายๆ Scope ที่ Client ต้องการใช้งานได้

Consent โดยเมื่อ Authorization Server ทำการ List Scope, List Permission ที่มี ทำการ Match กับการร้องขอจาก Client แล้ว Authorization Server จะทำการสร้าง Consent Screen เพื่อ Prompt ถามผู้ใช้งาน (Resource Owner) ว่า “TAMA ขอเข้าถึงข้อมูลของคุณ จะยินยอมไหม?” ซึ่งการทำงานลักษณะนี้ จะช่วยให้ Client สามารถร้องขอข้อมูลตาม Scope ต่างๆได้อย่างยืดหยุ่น สะดวก โดยผู้ใช้งาน (Resource Owner) จะต้องยินยอม (Consent) ด้วยตนเองเสมอ

กลับมาที่โฟลเดิม แต่เพิ่ม Scope และ Consent เข้าไป โดยทั่วไปแทบจะไม่มีอะไรเปลี่ยนนอกจากโฟลเริ่มต้น (1) ที่ Client จะทำ “การระบุ Scope” เพื่อบอก Authorization Server ว่าจะขอเข้าถึงข้อมูลที่เป้น Public Profile และ Contact ของผุ้ใช้งาน (Resource Owner) โดยแต่ละ Scope จะแบ่งโดยช่องว่าง ตามภาพ คือ Profile Contacts และโฟลที่ 2 คือ Authorization Server จะนำ Scope ไปสร้าง Consent Screen เพื่อแจ้งกับผู้ใช้งาน (Resource Owner) ว่า “Client ต้องการขอข้อมูล Public Profile และ Contact ของคุณนะ จะว่ายังไงครับ?” หากผู้ใช้งานกด “Yes” ก็จะเข้าตามโฟลเดิม เพื่อส่งข้อมูลกลับไปยัง Client Application

จากแนวทางนี้ TAMA สามารถร้องขอ Service อื่นๆเพิ่มเติมไปยัง Authorization Server ของ Google ได้อีก เช่น การเข้าถึง Calendar, เข้าถึง E-Mail ต่างๆ เป็นต้น ตาม Scope ที่ Google มีไว้ให้ใช้งาน เริ่มง่ายใช่ไหมครับ 🙂 แต่เอาตรงๆ นี่ยังไม่ได้เริ่ม OIDC เลย ดูละน่าจะอีกยาว เพื่อไม่ให้บทความยาวและหนักหัวจนเกินไป บทนี้จะขอจบคร่าวๆ แค่นี้ก่อน และจะมาลงรายละเอียดและครอบคลุมมากขึ้นอีกใน Blog OAuth มีกี่โฟลและทำงานกับ OIDC อย่างไร? ครับ!

จากโฟลที่แสดงไป ผมเชื่อว่าทุกท่านจะเห็นโฟลการทำงานทั้งหมดของ OAuth Authorization Code Flow และเข้าใจศัพท์ต่างๆมากขึ้น ไม่ งง เหมือนที่ผมเคย งง มาก่อนนะครับ 🙂

 


Leave a Reply