PKCE ชุดเกราะสำหรับ Authorization Code flow

Benjawan S.
4 min readDec 27, 2022

--

Lets Go Fight GIF By Juanfran

ก่อนที่จะไปอธิบายว่าทำไม PKCE (Proof Key for Code Exchange) ถึงเปรียบเสมือนชุดเกราะให้กับ Authorization Code flow อย่างแรกเราต้องมาทำความเข้าใจตัว PKCE กับ Auhtorization Code flow กันก่อนว่ามันคืออะไร 🤔🤔

🥊 มาทำความรู้จักกับ Authorization Code flow กัน! 🥊

ตัว Authorization Code flow นั้นถือว่าเป็น Grant Type ประเภทหนึ่งของ OAuth2.0 แต่ในบทความนี้เราจะไม่ได้ลงลึกถึง OAuth2.0 เท่าไหร่ แต่จะขออธิบายบทบาท (Roles) ที่มีใน OAuth เพิ่มเติมก่อนจะไปดูการทำงานของตัว Auhtorization Code flow กัน โดยที่บทบาทใน OAuth จะมีอยู่ 4 บทบาทด้วยกัน ได้แก่

  1. Resource Owner เป็นเจ้าของ Resource เป็นผู้ที่มีสิทธิ์เข้าถึง Resource รวมไปถึงอนุญาตให้เข้าถึง Resource ได้ ปกติมักจะถูกเรียกว่าเป็น Enduser
  2. Resource Server เป็น Server ที่เก็บรวบรวมและมีการป้องกันการเข้าถึง Resource ดังกล่าวไว้
  3. Client เป็น Application ปลายทางที่ต้องการร้องขอการเข้าถึง Resource
  4. Authorization Server เป็น Server ที่ทำหน้าที่ issue token สำหรับใช้เข้าถึงตัว Resource รวมไปถึงตรวจสอบความถูกต้องในการเข้าถึง Resource Server ผ่าน token ที่ได้ถูกกำหนดสิทธิ์ไว้ภายใน

เมื่อเราทราบบทบาทที่มีใน OAuth แล้วเรามาเริ่มดูการทำงานของตัว Authorization Code flow กันเลย

How authorization code flow work

1. Application ทำการ request ไปยัง /authorize endpoint ที่ตัว Authorization Server โดยมีการกำหนด URL ดังต่อไปนี้

[GET] https://authorization-server.com/oauth2/authorize
?response_type=code
&client_id=AC2104EQ651
&redirect_uri=https%3A%2F%2Fresource-owner.com%2Fcallback
&scope=user.profile+user.status
&state=DSKsc39snxZDhle102ri
  • response_type จะเป็นคำว่า code ซึ่งเป็นตัวที่บอกว่าเราใช้ Authorizatoin Code
  • client_id เป็นตัวที่ระบุตัวตนของ Application กับ Authorization Server
  • redirect_uri เป็น URI ที่ Authorization Server จะตอบกลับมาหลังจัดการ request เรียบร้อยแล้ว
  • scope เป็น scope ที่ใช้ระบุ permission ที่ Application จะร้องขอ
  • state เป็น random string ที่ใช้ตรวจสอบค่าที่ส่งกลับมาหลังจัดการ request เรียบร้อยแล้ว ใช้เพื่อป้องกัน CRSF Attacks

2. Authorization Server ทำการ redirect ไปยังหน้า login เพื่อให้ Enduser กรอกข้อมูล

3. Enduser ทำการ login และ consent เพื่อมอบสิทธิ์ให้การเข้าถึง Resource

4. Authorization Server redirect Authorization Code และ State กลับไปหา Application ต้นทางผ่าน redirect_uri ที่ได้กำหนดไว้ใน step ที่ 1 ซึ่งเราสามารถนำ State ที่ส่งกลับมา ไป recheck กับ State ที่เราส่งไปว่าตรงกันมั้ย

5. Application นำ Authorization Code ที่ได้รับกลับมาไป issue token ที่ /token endpoint โดยมีการกำหนด URL ดังต่อไปนี้

[POST] https://authorization-server.com/oauth2/token
?grant_type=authorization_code
&client_id=AC2104EQ651
&redirect_uri=https%3A%2F%2Fresource-owner.com%2Fcallback
&code=Odeied84kdEUF2s
  • grant_type เป็นตัวที่บอกว่าเราใช้ Authorizatoin Code
  • client_id เป็นตัวที่ระบุตัวตนของ Application กับ Authorization Server
  • redirect_uri เป็น URI เดียวกันกับ step ที่ 1 ที่ request เข้ามา
  • code เป็นค่า Authorization Code ที่ได้รับจาก step ที่ 5

6. Authorization Server ทำการ issue token และส่ง Access Token, Refresh Token, ID Token กลับไปให้

7. Application นำ Access Token ไปร้องขอการเข้าถึง Resource กับ Resource Owner

8. Resource Owner นำ Access Token ที่ได้มาไปตรวจสอบสิทธิ์ในการเข้าถึง Resource กับ Authorization Server

9. Authorization Server ตรวจสอบและตอบกลับผลไปให้ Resource Server

10. หาก Resource Server ได้รับการตอบกลับว่า Access Token นั้นถูกต้องก็จะไปดึงเอาข้อมูล Resource ตามที่ได้มีการร้องขอเข้ามาแล้วตอบกลับไปให้ Application

จะเห็นได้ว่าสิ่งที่ Authorization Server ตอบกลับมาให้ Application ไม่ใช่ Access Token เลยทีเดียว แต่จะเป็น Authorization Code ซึ่งเป็น code ที่ช่วยป้องกันการรั่วไหลของข้อมูลหากส่งผ่าน Access Token ไปในทันที แต่นำเอา Authorization Code ที่ได้รับมาไป issue token ต่ออีกรอบแทน ซึ่งการทำงานด้านบนก็ดูจะไม่มีปัญหาอะไร แต่! จะเกิดอะไรขึ้นถ้า Application ที่เราไปเชื่อมต่อดันเป็น Application ที่ผู้ไม่ประสงค์ดีพยายามดักจับ Authorization Code เพื่อนำไป issue token ซะเอง 😱😱

How atacker inject the request and stole the authorization code
Prince Harry Mic Drop GIF

🦾 PKCE (Proof Key for Code Exchange) ชุดเกราะพลังรบของพวกเรา! 🦾

PKCE หรือ Proof Key for Code Exchange เป็นส่วนขยายของ​ Authorization Code ที่ช่วยป้องกัน CSRF Token รวมไปถึง Authorization Injection Code

เพื่อป้องการการโจมตีที่อาจเกิดขึ้นตัว PKCE จะเป็นการสร้าง cryptographic random string ขึ้นมาตัวหนึ่งที่ชื่อว่า Code Verifier จากนั้นนำไปผ่านการ hashing แปลงเป็น Code Challenge แล้วนำค่าที่ได้ส่งไปในทุกครั้งที่ยิง request /authorize และพอถึง step การ issue token ก็นำตัว Code Verifier ส่งเพิ่มเข้าไปตอนยิง request /token โดยตัว Authorization Server จะนำค่าที่ได้รับไปตรวจสอบกับ Code Challenge ที่เราส่งมาก่อนหน้านี้ ถ้าเป็นค่าเดียวกันจึงจะยอม issue token กลับไปให้

มาถึงตรงนี้เราก็พอจะเข้าใจหลักการทำงานของ Authorization Code flow with PKCE บ้างแล้ว ซึ่งตัว Code Verifier กับ Code Challenge นั้นจะมีเพียง Application ต้นทางจริงๆ เท่านั้นที่สามารถรู้ได้ ต่อไปเราไปดูวิธีการทำงานในแต่ละ step เพิ่มเติมกันอีกซักนิดดีกว่า

How authorization code flow work with PKCE

1. Application ทำการ generate Code Verifier และ Code Challenge โดยเก็บ Code Verifier ไว้เพื่อนำไปใส่ตอน issue token ในภายหลัง

2. Application ทำการ request ไปยัง /authorize endpoint ที่ตัว Authorization Server โดยเพิ่ม Code Challenge เข้าไปใน URL ตามด้านล่าง

[GET] https://authorization-server.com/oauth2/authorize
?response_type=code
&client_id=AC2104EQ651
&redirect_uri=https%3A%2F%2Fresource-owner.com%2Fcallback
&scope=user.profile+user.status
&state=DSKsc39snxZDhle102ri
&code_challenge=OHpkshaUdhj1JpdocvO4BfFIluJptw824zUwpM4o0xs

3. Authorization Server ทำการ redirect ไปยังหน้า login เพื่อให้ Enduser กรอกข้อมูล

4. Enduser ทำการ login และ consent เพื่อมอบสิทธิ์ในการเข้าถึง Resource

5. Authorization Code redirect Authorization Code และ State กลับไปหา Application ต้นทางผ่าน redirect_uri ที่ได้กำหนดไว้ใน step ที่ 1 ซึ่งเราสามารถนำ State ที่ส่งกลับมา ไป recheck กับ State ที่เราส่งไปว่าตรงกันมั้ย

6. Application นำ Authorization Server ที่ได้รับกลับมานำไป issue token ที่ /token endpoint โดยเพิ่ม Code Verifier ที่เรา generate เมื่อ step ที่ 1 เข้าไปใน URL ตามด้านล่าง

[POST] https://authorization-server.com/oauth2/token
?grant_type=authorization_code
&client_id=AC2104EQ651
&redirect_uri=https%3A%2F%2Fresource-owner.com%2Fcallback
&code=Odeied84kdEUF2s
&code_verifier=imcodeverifier

7. Authorization Server ตรวจสอบ Code Verifier กับ Code Challenge

8. หากตรวจสอบแล้วถูกต้อง Authorization Server ทำการ issue token และส่ง Access Token, Refresh Token, ID Token กลับไปให้

9. Application นำ Access Token ไปร้องขอการเข้าถึง Resource กับ Resource Owner

10. Resource Owner นำ Access Token ที่ได้มาไปตรวจสอบสิทธิ์ในการเข้าถึง Resource กับ Authorization Server

11. Authorization Server ตรวจสอบและตอบกลับผลไปให้ Resource Server

12. หาก Resource Server ได้รับการตอบกลับว่า Access Token นั้นถูกต้องก็จะไปดึงเอาข้อมูล Resource ตามที่ได้มีการร้องขอเข้ามาแล้วตอบกลับไปให้ Application

Step ที่ทำตัวหนาไว้คือส่วนที่แตกต่างกับ Authorization Code Flow ปกติ

Game Defend GIF By Xbox

สรุป

การใช้ Authorization Code เพียงอย่างเดียวอาจจะไม่ปลอดภัยเท่าไหร่หากถูกหมายตาจากผู้ประสงค์ร้าย แต่เราก็สามารถนำ PKCE มาช่วยเพิ่มความปลอดภัยได้โดยการ generate Code Verifier กับ Code Challenge แปะเพิ่มเข้าไปใน request เพื่อใช้ยืนยันและตรวจสอบ request ว่ามาจาก Application ต้นทางจริงๆ 😎😎

Reference

--

--