การตรวจสอบ สิทธิ์เป็น Hypermedia API

Hypermedia API User Authentication — กระบวนการในการตอบคำถามว่าใครเป็นใคร — มีการพัฒนาอย่างมากในช่วงไม่กี่ปีที่ผ่านมา ตั้งแต่เริ่มต้นความปลอดภัยของคอมพิวเตอร์จนกระทั่งเมื่อไม่นานมานี้ การตรวจสอบสิทธิ์ผู้ใช้ได้รับการปกป้องด้วยรหัสผ่านเป็นหลัก สิ่งนี้เกี่ยวข้องกับการขอชื่อผู้ใช้และตรวจสอบว่าผู้ใช้ที่อยู่เบื้องหลังชื่อนั้นทราบรหัสผ่านที่เชื่อมโยงกับชื่อนั้น

เมื่อพลังการประมวลผลเพิ่มขึ้น และการโจมตีมีความซับซ้อนมากขึ้น เห็นได้ชัดว่ารหัสผ่านไม่เพียงพอ ขณะนี้การรับรองความถูกต้องเกี่ยวข้องกับวิธีการต่างๆ ที่เรียกว่า Multi-Factor Authentication ขึ้นอยู่กับภูมิภาค อุตสาหกรรม และกรณีการใช้งาน ปัจจัยเหล่านี้มักจะแตกต่างกัน เรายังอาศัยบุคคลอื่นในการพิจารณาว่าใครคือผู้ใช้ การเข้าสู่ระบบโซเชียลเป็นตัวอย่างที่ดี

ซึ่งหมายความว่าสิ่งที่เคยเป็นแบบสอบถามง่ายๆ ในการตรวจสอบความถูกต้องของข้อมูลในฟอร์ม ในขณะนี้คือการเดินทางของผู้ใช้ที่ยาวนาน อาจเกี่ยวข้องกับการเยี่ยมชมเว็บไซต์อื่นๆ (Facebook หรือ Google) การเปิดแอปอื่นๆ (Duo, BankID) และการคลิกรูปภาพทั้งหมดที่แสดงสัญญาณไฟจราจร (ไม่มีความคิดเห็น)

บริการรับรองความถูกต้องเป็นเว็บไซต์ที่ซับซ้อนซึ่งแนะนำผู้ใช้ตลอดขั้นตอนเหล่านี้

ที่ Curity เราถูกถามคำถามนี้หลายครั้ง: ทำไมเราจึงไม่ได้รับ API เพื่อตรวจสอบผู้ใช้ของเรา เหตุผลเบื้องหลังคำถามนั้นง่ายมาก: ลูกค้าของเราไม่ต้องการส่งผู้ใช้ไปยังเว็บไซต์รับรองความถูกต้องจากแอพ แต่เก็บไว้ในแอพ อย่างไรก็ตาม คำตอบนั้นไม่ง่ายนัก การตรวจสอบสิทธิ์ผู้ใช้นั้นถือเป็นเรื่องปกติ:

  • ผู้ใช้จะปฏิบัติตามขั้นตอนที่กำหนดไว้ล่วงหน้าเพื่อระบุตัวตนให้สมบูรณ์
  • เบราว์เซอร์จะทำให้แน่ใจว่าเป็นกรณีนี้
  • ไม่มีบุคคลอื่นใดสามารถสกัดกั้นข้อความและใช้ประโยชน์จากผลลัพธ์สุดท้ายได้

ความคาดหวังเหล่านี้ทำให้ API ค่อนข้างแตกต่างออกไป ประการแรก เนื่องจากการรับรองความถูกต้องคือการเดินทาง ไคลเอ็นต์ API จึงต้องปฏิบัติตามโปรโตคอลเมื่อสื่อสารกับ API ต้องมีจุดเริ่มต้นและจุดสิ้นสุดที่แน่นอน สิ่งนี้ตรงกันข้ามอย่างสิ้นเชิงกับวิธีการเช่น GraphQL และ REST ระดับล่าง (ตามที่กำหนดโดยRichardson Maturity Model ) ทั้งสองได้รับการออกแบบมาเพื่อให้ผู้โทรเข้าสู่ทรัพยากรในแบบที่ผู้โทรต้องการ

ตัวแทนไฮเปอร์มีเดีย

การถอยกลับไปมองจากระยะไกลสามารถให้ข้อมูลเชิงลึกที่สำคัญบางอย่างได้ บทความนี้เริ่มต้นด้วยการอธิบายวิธีการรับรองความถูกต้องบนเว็บ โดยมีเว็บไซต์แบบเก็บสถานะที่นำผู้ใช้ผ่านขั้นตอนการตรวจสอบสิทธิ์ ในบริบทนี้ เว็บเบราว์เซอร์เป็นไคลเอ็นต์ API โดยใช้ REST และ HTML เพื่อนำเสนออินเทอร์เฟซผู้ใช้ นี่คือ Hypermedia API ซึ่งมีการพูดคุยกันใน Nordic API หลายครั้งก่อนหน้านี้ (สิ่งที่น่าสนใจเป็นพิเศษคือ “ การใช้ Hypermedia เพื่อออกแบบ UI ที่ขับเคลื่อนด้วยเหตุการณ์ ” ตามการนำเสนอของ Asbjørn Ulsberg ที่การประชุมสุดยอดแพลตฟอร์มของ Nordic APIs) Hypermedia ให้ความสำคัญกับกระบวนการที่เซิร์ฟเวอร์และไคลเอนต์ต้องดำเนินการควบคู่กันไปตามโฟลว์ ถ้าเราแทนที่ HTML ด้วย JSON และจัดโครงสร้างให้สอดคล้องกันมากขึ้น เรามีวิธีที่สมบูรณ์แบบในการออกแบบ API การพิสูจน์ตัวตน

ขั้นตอนพื้นฐาน

มาดูตัวอย่างวิธีการแสดงหน้าจอรหัสผ่านชื่อผู้ใช้อย่างง่ายโดยใช้ HTML:

<body class="login body-light">
   <main class="container clearfix" role="main">
       <div class="login-well form-light">
           <img class="login-logo" src="https://19yw4b240vb03ws8qm25h366-wpengine.netdna-ssl.com/assets/images/curity-logo.svg" alt="Logo" title="Logo" role="presentation">
           <form method="post" action="/dev/authn/authenticate/htmlSql">
               <div class="form-field">
                   <label for="userName" class="">Username</label>
                   <input type="text" name="userName" class="field-light" autocapitalize="none" autofocus>
               </div>
               <div class="form-field">
                   <label for="password" class="">Password</label>
                   <input type="password" name="password" class="field-light">
               </div>
               <button type="submit" class="button button-fullwidth  mt2">Login</button>
               <div class="login-actions">
                   <a href="/dev/authn/authenticate/htmlSql/forgot-password">Forgot your password?</a>
 
                   <a href="/dev/authn/register/create/htmlSql" class="mt2">
                       <i class="icon ion-android-person-add"></i>
                       Create account </a>
               </div>
           </form>      
       </div>
   </main>
</body>

ตอนนี้ มาดูหน้าจอเดียวกันโดยใช้ประเภทสื่อ JSON:

{
       "type": "authentication-step",
	"links": [
    	{
        	"href": "/dev/authn/authenticate/htmlSql/forgot-password",
        	"rel": "forgot-password",
        	"title": "Forgot your password?"
    	},
       {
        	"href": "/dev/authn/register/create/htmlSql",
        	"rel": "register-create",
        	"title": "Create account"
    	}
	],		
	"actions": [
    	{
        	"template": "form",
        	"kind": "login",
        	"title": "Login",
        	"model": {
            	  "href": "/dev/authn/authenticate/htmlSql",
            	  "method": "POST",
            	  "type": "application/x-www-form-urlencoded",
            	  "actionTitle": "Login",
            	  "fields": [
                	{
                    	"name": "userName",
                    	"type": "username",
                    	"label": "Username"
                	},
                	{
                    	"name": "password",
                    	"type": "password",
                    	"label": "Password"
                	}
            	]
        	}
    	}
	]
}

สังเกตว่ามีการดำเนินการที่เป็นไปได้อย่างไร ควรแสดงผลสองช่องและสามารถส่งได้ แต่ยังมีลิงก์ที่สามารถแสดงผลได้โดยที่ผู้ใช้สามารถใช้เส้นทางอื่นผ่านโฟลว์การตรวจสอบสิทธิ์ได้หากจำเป็น

ด้วยวิธี Hypermedia เซิร์ฟเวอร์สามารถควบคุมโฟลว์ได้ด้วยจุดเข้าและออกเพียงจุดเดียว แต่นำเสนอตัวเลือกแก่ผู้ใช้ตลอดโฟลว์

เซิร์ฟเวอร์จะแนะนำลูกค้าด้วยรายละเอียดเกี่ยวกับวิธีการสร้างแต่ละหน้าจอ แต่มีตัวเลือกจำนวนหนึ่งเท่านั้นที่จะนำไปใช้ ไม่เหมือนกับ HTML ที่มาร์กอัป การจัดรูปแบบ และ JavaScript สร้างเฟรมเวิร์กขนาดใหญ่เพื่อนำไปใช้ Hypermedia API เป็น DSL ขนาดเล็กที่มีข้อจำกัดอย่างดีสำหรับการแสดงผลอินเทอร์เฟซผู้ใช้

ค่อนข้างชัดเจนว่าการรับรองความถูกต้องเป็นเครื่องสถานะที่เซิร์ฟเวอร์แนะนำผู้ใช้ผ่านหลายสถานะเพื่อให้กระบวนการตรวจสอบสิทธิ์เสร็จสมบูรณ์ ฉันแนะนำให้อ่าน Designing a True REST State Machine สำหรับคำแนะนำในเชิงลึกที่ว่าทำไม Hypermedia จึงสามารถนำเสนอตัวเองได้ดีสำหรับจุดประสงค์นี้

ขั้นตอนอัตโนมัติ

ไม่ใช่ทุกขั้นตอนในกระบวนการตรวจสอบสิทธิ์ที่จำเป็นต้องมีการโต้ตอบกับผู้ใช้ ตัวอย่างที่ดีคือกระบวนการเลือกตั้ง โพลเกิดขึ้นเมื่อเรารอให้ผู้ใช้ดำเนินการนอกแบนด์ เช่น เมื่อผู้ใช้เลือกลิงก์อีเมลเป็นวิธีการตรวจสอบสิทธิ์ ผู้ใช้ป้อนที่อยู่อีเมล จากนั้นกระบวนการเข้าสู่ระบบจะรอให้ผู้ใช้คลิกลิงก์นั้น เมื่อผู้ใช้คลิกลิงก์ สถานะเซิร์ฟเวอร์จะได้รับการอัปเดต และการรับรองความถูกต้องสามารถดำเนินการต่อได้ ในช่วงเวลานี้ เราต้องแนะนำให้ลูกค้าสำรวจเซิร์ฟเวอร์เป็นระยะเพื่อดูว่าผู้ใช้คลิกลิงก์หรือไม่ โดยการแนะนำประเภทตัวแทนของ “การสำรวจความคิดเห็น” ลูกค้าสามารถแยกวิเคราะห์ข้อความและรู้ว่ามีการดำเนินการที่จะใช้โดยที่ผู้ใช้ไม่โต้ตอบกับข้อความนั้น

{
  "type": "polling-step",
  "properties": {
	"recipientOfCommunication": "johnxxxx@xxxxple.com",
	"status": "pending"
  },
  "actions": [
    {
  	"template": "form",
  	"kind": "poll",
  	"model": {
    	  "href": "/authenticate/email1/link-wait",
    	  "method": "GET"
       }
    },
    {
  	"template": "form",
  	"kind": "cancel",
  	"title": "Restart the process",
  	"model": {
    	  "href": "/authenticate/email1",
    	  "method": "GET",
    	  "type": "application/x-www-form-urlencoded",
    	  "actionTitle": "Restart the process"
  	}
     }
  ]
}

สถานะpendingแนะนำให้ลูกค้าดำเนินการต่อไป ตราบใดที่ polling-step มีการนำเสนอ ลูกค้าจะยังคงทำการสำรวจความคิดเห็น

ในหน้าเว็บปกติ นี่อาจเป็นไคลเอนต์ JavaScript ที่สำรวจเซิร์ฟเวอร์เพื่อรอการตอบสนองบางอย่าง แต่สำหรับ Hypermedia แม้แต่กรณีนั้นก็ดีขึ้น ลูกค้าจะได้รับการตอบสนองที่กำหนดไว้อย่างดีซึ่งเป็นไปตามสคีมาเดียวกัน ไม่ว่าผู้ใช้จะตรวจสอบสิทธิ์โดยใช้อีเมล, SMS หรือวิธีอื่นๆ

แบบแผน

ตรงกันข้ามกับแอปพลิเคชันการตรวจสอบสิทธิ์บนเว็บทั่วไป คู่ Hypermedia API ต้องมีแผนผังอย่างเคร่งครัด ลูกค้าจำเป็นต้องเข้าใจการเป็นตัวแทน (การตอบสนอง) แต่ละครั้งโดยการอ่านประเภทระดับบนสุด จากนั้นจึงรู้ว่ารายการใดบ้างที่อาจมีอยู่ในการเป็นตัวแทนนั้น นี่ไม่ใช่กรณีบนหน้าเว็บปกติ เนื่องจากเบราว์เซอร์ถูกจำกัดโดยสคีมา HTML เท่านั้น ไม่ใช่ชุดย่อยที่จำเป็นสำหรับการตรวจสอบสิทธิ์ มันไปโดยไม่บอกว่ามันจะเป็นข้อกำหนดที่ไม่สมเหตุสมผลที่จะให้แอปพลิเคชันมือถือใช้บางอย่างเช่น HTML เพื่อให้สามารถทำโฟลว์การรับรองความถูกต้องได้ แต่เราทำให้สคีมามีขนาดเล็กที่สุดและสามารถคาดเดาได้อย่างเต็มที่ ไม่ได้หมายความว่าแอปพลิเคชันรู้ว่าจะเกิดอะไรขึ้นต่อไป แต่รู้ว่าจะทำอย่างไรกับข้อมูลปัจจุบัน

ตัวอย่าง:

type: authentication-step
purpose: interactive user step during authentication
possible top-level elements: properties, actions, messages, links

ตัวอย่าง:

type: polling-step
purpose: automatic step
possible top-level elements: properties, actions

สิ่งนี้สามารถทำให้เป็นทางการได้โดยใช้ภาษาสคีมาที่เหมาะสม ที่ Curity เราได้กำหนดนิยามสคีมาของเราใน JSON Schema

การเจรจาต่อรองเนื้อหา

เมื่อสร้าง API แบบไดนามิก เช่น Hypermedia Authentication API สิ่งสำคัญคือต้องมั่นใจว่าไคลเอ็นต์สามารถควบคุมสิ่งที่สนับสนุนได้ HTTP มีกลไกที่ยอดเยี่ยมสำหรับสิ่งนี้ที่เรียกว่าการเจรจาต่อรองเนื้อหา

การเจรจาต่อรองเนื้อหาคือเมื่อไคลเอ็นต์บอกเซิร์ฟเวอร์ว่าสามารถยอมรับเนื้อหาประเภทใดได้ จากนั้นเซิร์ฟเวอร์จะพยายามให้บริการเนื้อหาในรูปแบบที่เหมาะสม ตัวอย่างเช่น เมื่อขอรูปภาพ เบราว์เซอร์อาจส่ง:

GET  https://example.com/assets/images/foo.jpg
Accept image/webp,*/*

ซึ่งหมายความว่าชอบรูปภาพในรูปแบบ webp แต่ถ้าไม่มี จะยอมรับอะไรก็ได้ ( */*) รายการนี้อาจมีความยาว โดยสรุปรูปแบบเฉพาะทั้งหมดที่รองรับ ที่น่าสนใจคือ นามสกุลไฟล์ (.jpg) ใช้ไม่ได้จริงๆ ในที่นี้ มันซ้ำซาก และมีการนำเสนอที่ยอดเยี่ยมจาก Erik Michaels-Ober: การเจรจาเนื้อหาสำหรับ REST APIs ซึ่งเขาอธิบายรายละเอียดเพิ่มเติมเกี่ยวกับเรื่องนี้ ฉันยังแนะนำให้อ่านบทนำของ Bill Doerrfeld เกี่ยวกับการเจรจาเนื้อหาเกี่ยวกับ Nordic APIs ที่นี่

เมื่อพูดถึง Hypermedia API หรือ REST API ใดๆ สำหรับเรื่องนั้น ประเด็นของการเจรจาเนื้อหาคือเพื่อให้ลูกค้าสามารถระบุได้ว่ารองรับ API หรือไม่

เมื่อเราพูดถึงการพิสูจน์ตัวตน มีหลายวิธีที่ผู้ใช้สามารถพิสูจน์ตัวตนได้ บางส่วนเป็นกลไกการพิสูจน์ตัวตนตามแบบฟอร์มล้วนๆ โดยที่ผู้ใช้ป้อนข้อมูลประจำตัวหรือตัวระบุบางส่วน และเซิร์ฟเวอร์ตรวจสอบความถูกต้อง แต่ยังมีวิธีการที่เกี่ยวข้องมากกว่าด้วย ซึ่งอาจต้องการให้ไคลเอ็นต์ดำเนินการตามขั้นตอนเพิ่มเติม เช่น การสื่อสารกับระบบปฏิบัติการหรือเบราว์เซอร์เพื่อดำเนินการ พิสูจน์ตัวตน แบบไบโอเมตริก ซึ่งอาจเกินความสามารถของลูกค้าบางราย

ดังนั้น ด้วยการใช้การเจรจาเนื้อหา เราจึงสามารถสร้างสัญญาระหว่างลูกค้าและเซิร์ฟเวอร์ได้

GET  https://idp.example.com/api/authenticate
Accept application/vnd.auth+json

สิ่งนี้จะบอกเซิร์ฟเวอร์ว่าไคลเอนต์ต้องการเริ่มโฟลว์การรับรองความถูกต้องโดยใช้ Hypermedia API ที่กำหนดโดยapplication/vnd.auth+jsonประเภทสื่อ นอกจากนี้ยังบอกเซิร์ฟเวอร์ว่าไคลเอนต์สามารถจัดการเนื้อหาที่ได้รับ

รองรับหลายภาษา

โดยปกติเว็บเซิร์ฟเวอร์จะรับผิดชอบในการแปลเนื้อหาที่ให้บริการไปยังเบราว์เซอร์ ซึ่งทำได้โดยใช้รูปแบบการเจรจาเนื้อหา เบราว์เซอร์จะส่ง Accept-Language ส่วนหัวเพื่อระบุภาษาและตำแหน่งที่ตั้งที่รองรับในรายการแบบถ่วงน้ำหนัก และเซิร์ฟเวอร์พยายามอย่างเต็มที่เพื่อดำเนินการตามนี้

Accept-Language en-US,en;q=0.5

เมื่อสร้าง Hypermedia API ไม่มีเหตุผลที่จะใช้กลไกอื่น ลูกค้าสามารถบอกเซิร์ฟเวอร์ว่าข้อความในเนื้อหาควรเป็นภาษาท้องถิ่นอย่างไร อย่างไรก็ตาม สามารถให้อิสระมากขึ้นได้ด้วยการตอบกลับด้วยคีย์ข้อความ เพื่อให้ลูกค้าสามารถแปลข้อความได้เองหากต้องการ

ตัวอย่างเมื่อ Accept-Language en-US;en;q=05.:

{
  "type": "authentication-step",
  "actions": [
	{
  	"template": "selector",
  	"kind": "authenticator-selector",
  	"title": "Select Authentication Method",

Example when Accept-Language sv-SE;sv;q=05.
{
  "type": "authentication-step",
  "actions": [
	{
  	"template": "selector",
  	"kind": "authenticator-selector",
  	"title": "Välj inloggningsmetod",

ความปลอดภัย

ส่วนสำคัญของการสร้าง API การตรวจสอบความถูกต้องคือการรักษาความปลอดภัย สิ่งสำคัญคือต้องไม่อนุญาตให้แอปพลิเคชันโดยพลการบนอินเทอร์เน็ตเข้าถึง API ของคุณ เนื่องจากมีความเป็นไปได้สูงที่จะนำไปใช้ในทางที่ผิด คุณไม่ต้องการให้ผู้โจมตีรวบรวมข้อมูลประจำตัวจากไซต์หนึ่งโดยการสร้างไซต์ฟิชชิ่งและลองใช้กับ API ของคุณเพื่อเข้าถึง API ของคุณโดยตรง

เมื่อใช้การเข้าสู่ระบบบนเบราว์เซอร์ปกติ (ไม่ใช่ API) จะเป็นมาตรฐานในการบล็อกเฟรมของโฟลว์การตรวจสอบสิทธิ์จากใครก็ได้ยกเว้นไซต์ที่อนุญาตพิเศษโดยใช้นโยบายความปลอดภัยเนื้อหา (CSP) (แน่นอนว่า CSP ไม่ได้ป้องกันฟิชชิ่งแต่ป้องกัน XSS) แต่เมื่อส่ง API แทน กลไกของเบราว์เซอร์เหล่านี้ใช้งานน้อยลง Hypermedia API User

แน่นอนว่าควรใช้ OAuth เพื่อปกป้อง API นี้ อย่างไรก็ตาม OAuth แบบเก่าธรรมดาอาจไม่เพียงพอในสถานการณ์นี้ โฟลว์ การโต้ตอบ ของผู้ใช้ ใน OAuth ได้รับการออกแบบโดยคำนึงถึงเบราว์เซอร์เป็นหลัก มีข้อสันนิษฐานพื้นฐานที่ว่าสิ่งต่างๆ เช่น CORS ได้รับการบังคับใช้อย่างถูกต้องโดยเบราว์เซอร์ และเบราว์เซอร์สามารถพิสูจน์ได้ว่าไซต์นั้นกำลังทำงานอยู่บนโดเมนที่กล่าวไว้ สมมติฐานเหล่านี้แตกหักเมื่อใช้แนวทางที่ขับเคลื่อนด้วย API ล้วนๆ

ฉันแนะนำให้อ่านเอกสารทางเทคนิคของเราเกี่ยวกับโมเดลความปลอดภัยของ Hypermedia Authentication APIที่เราสร้างที่ Curty จะพาคุณผ่านเรื่องราวในเชิงลึก

Hypermedia Authentication API: อนาคตของการรับรองความถูกต้อง

การตรวจสอบสิทธิ์ด้วย API ถือเป็นจอกศักดิ์สิทธิ์สำหรับนักพัฒนามือถือมาช้านานแล้ว และเมื่อเร็วๆ นี้รวมถึงนักพัฒนาเว็บด้วย เราจำเป็นต้องรับฟังและจัดเตรียมโปรโตคอลที่ปลอดภัยสำหรับกรณีการใช้งานเหล่านี้เพื่อป้องกันไม่ให้โซลูชันที่ไม่ปลอดภัยที่เกิดขึ้นเอง ที่ Curity เราทำงานกับมาตรฐานต่างๆ เช่น OAuth และ OpenID Connect และเมื่อเกิดข้อผิดพลาด เราก็ทำงานร่วมกับองค์กรมาตรฐานเพื่อพัฒนาโซลูชันใหม่ๆ เราเชื่อว่า Hypermedia Authentication API มาตรฐานคืออนาคตของการรับรองความถูกต้องผ่านมือถือและเว็บ

ทั้งนี้บริษัทเคแอนด์โอ จึงได้มุ่งเน้นการจัดการแก้ไขปัญหา จัดการเอกสาร ด้านเอกสารขององค์กรมาอย่างยาวนาน และ ให้ความสำคัญกับด้านงานเอกสาร ต่อลูกค้าเป็นอย่างดี จนถึงปัจจุบันก็ได้ความยอมรับจากองค์กร ขนาดใหญ่ ขนาดกลาง และขนาดเล็กมากมาย จึงใคร่ขออาสาดูและปัญหาด้านเอกสารให้กับองค์กรของท่านอย่างสุดความสามารถ เพราะเราเป็นหนึ่งในธุรกิจ ระบบจัดเก็บเอกสาร ที่ท่านไว้ใจได้

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

เรามีแอดมินคอยคอบคำถาม 24 ชั้วโมงที่ Line OA ให้คำปรึกษาด้านวางระบบจัดการเอกสารอิเล็กทรอนิกส์  EDMS โดยทีมงานผู้เชี่ยวชาญจาก K&O

ที่มีประสบการณ์มากว่า 15 ปี รวมถึงซอฟต์แวร์ระดับโลก ติดต่อ 0 2 – 8 6 0 – 6 6 5 9 หรือ E m a i l : c s @ k o . i n . t h

หากท่านมีความสนใจ บทความ หรือ Technology สามารถติดต่อได้ตามเบอร์ที่ให้ไว้ด้านล่างนี้
Tel.086-594-5494
Tel.095-919-6699

Related Articles