เนื้อหาต่อไปนี้เรามาดูการกำหนดให้ API ของเรานั้น มีการจำกัดการเข้าถึงข้อมูล เช่น สามารถเรียกใช้งาน
API นี้ได้เมื่อมีการระบุ username และ password ถูกต้อง หรือ เข้าถึง API ได้เฉพาะจาก IP ที่ระบุไว้แล้ว
เท่านั้น แบบนี้เป็นต้น
บทความนี้เป็นบทความต่อเนื่อง สามารถทบทวนบทความก่อนหน้าได้ที่
เพิ่มความสามารถ RESTful Services ใน CodeIgniter อย่างง่าย
https://www.ninenik.com/content.php?arti_id=809 via @ninenik
การจำกัดการเข้าถึงข้อมูล API ด้วย Basic Authentication และ Digest Authentication
การกำหนด Authentication ทั้งสองวิธีมีลักษณะการใช้งานคล้ายกัน แต่วิธี Digest Authentication จะมีความปลอดภัย
กว่า Basic Authentication โดยที่วิธี Digest Authentication รองรับการป้องกันการโจมตีในลักษณะการพยายามส่งค่า username
และ password เข้ามาซ้ำๆ ซึ่งวิธีแบบ Basic จะไม่รองรับในส่วนนี้
ทำความเข้าใจความแตกต่างเพิ่มเติมทั้งสองกรณีได้ที่ลิ้งค์นี้
สำหรับวิธีการจำกัดการเข้าถึงข้อมูล API ด้วย Basic Authentication และ Digest Authentication ในการใช้งาน RESTFul services
ข้างต้น สามารถทำได้ดังนี้
ให้ไปที่ไฟล์ rest.php ในโฟลเดอร์ apps > config ดังรูป
ส่วนที่ต้องแก้ไขมีคือ ให้หาส่วนของการตั้งค่า $config['rest_auth']
โดยค่าเดิมจะเป็น
$config['rest_auth'] = FALSE;
ให้เปลี่ยนเป็น
$config['rest_auth'] = 'basic'; // หรือ // $config['rest_auth'] = 'digest';
ในที่นี้เราจะใช้เป็น basic
จากนั้นส่วนของการตั้งค่า $config['auth_source']
โดยค่าเดิมจะเป็น
$config['auth_source'] = 'ldap';
ให้เปลี่ยนเป็น ค่าว่าง
$config['auth_source'] = '';
และส่วนการตั้งค่าต่อมาคือ $config['rest_valid_logins']
เป็นส่วนที่ใช้กำหนด username และ password สำหรับใช้งาน
โดยค่าเดิมจะเป็น
$config['rest_valid_logins'] = ['admin' => '1234'];
สามารถเปลี่ยนเป็นค่าอื่นตามต้องการ หรือเพิ่มค่าเข้าไปเพิ่มเติมได้ โดยเป็นข้อมูลที่อยู่ในรูปแบบ array
สมมติเราลองเพิ่ม username เป็น demo และ password เป็น test เข้าไปก็จะได้เป็น
$config['rest_valid_logins'] = ['admin' => '1234','demo' => 'test'];
เวลาที่เราทดสอบการใช้งาน หากต้องการให้เปลี่ยนค่าหรือต้องการทดสอบค่าใหม่ ให้เรามาเปลี่ยนค่า password
ในส่วนนี้ได้ ยกตัวอย่างเช่น เราทดสอบล็อกอินผ่านแล้ว ก็จะไม่ขึ้นการตรวจสอบอีก ดังนั้นถ้าต้องการทดสอบ
การตรวจสอบการล็อกอินใหม่อีกครั้ง ก็ให้มาเปลี่ยนค่า password สลับไปมา เพื่อจะได้ทดสอบได้
(ตั้งแต่ PHP 5.4 เราสามารถใช้รูปแบบปีกกาสี่เหลี่ยมแทนการกำหนดตัวแปรแบบ array ได้ เช่นจากเดิม
array('admin' => '1234','demo' => 'test') สามารถใช้เป็น ['admin' => '1234','demo' => 'test'] แทนได้)
เรามาลองทดสอบเรียก API ผ่าน url จากบราวเซอร์กันดู
/api/v1/provinces?fields=province_name
หลังจากมีการกำหนด Basic Authentication จะขึ้นแสดงสำหรับการเข้าใช้งานดังรูป
ทดสอบกรอกข้อมูลไม่ถูกต้อง ก็จะไม่สามารถเข้าถึง API นี้ได้ หรือกรณีเรากดปุ่ม Cancel
ก็จะแสดง HTTP status code เป็น 401 Unauthorized
พร้อมกับข้อความ error แจ้งดังรูป
เรามาดูวิธีการเรียกใช้งานที่ไม่ผ่าน url ทางบราวเซอร์โดยตรง หรือวิธีการใช้งานด้วย Requests for PHP
จากบทความ
เรียกใช้ Requests for PHP สำหรับใช้งาน HTTP library ใน codeigniter
https://www.ninenik.com/content.php?arti_id=701 via @ninenik
ให้สร้างไฟล์ทดสอบชื่อ Testrequest.php ในโฟลเดอร์ apps > controllers ดังรูป
และกำหนดโค้ดตัวอย่างดังนี้
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Testrequest extends CI_Controller { public function __construct() { parent::__construct(); $this->load->library('PHPRequests'); } public function index(){ $headers = array('Accept' => 'application/json'); $options = array('auth' => array('user', 'pass')); $response = Requests::get('http://localhost/learnci//api/v1/provinces', $headers, $options); echo "<pre>"; echo $response->status_code."<br>"; var_dump($response->status_code); // int(200) var_dump($response->headers['content-type']); // string(31) "application/json; charset=utf-8" var_dump($response->body); echo "</pre>"; } }
ทดสอบรันไฟล์เพื่อเรียก API
จะเห็นว่าในตัวอย่างโค้ดไฟล์ Testrequest.php เรากำหนด username เป็น user และ password เป็น pass
ซึ่งไม่ใช่ข้อมูลที่ถูกต้อง เพราะว่า API ของเราจำกัดการเข้าถึงแบบ Basic Authentication โดยใช้
username เป็น admin และ password เป็น 1234 ดังนั้นหลังจากรันไฟล์เพื่อทดสอบจึงขึ้นสถานะเป็น 401 Unauthorized
คือไม่ได้รับการรับรองการเข้าถึงข้อมูล ทีนี้เราลองเปลี่ยน username และ password ให้ถูกต้องในไฟล์ Testrequest.php
เป็นดังนี้
$options = array('auth' => array('admin', '1234'));
ทดสอบรันไฟล์ Testrequest.php อีกครั้ง ดังรูป
ผลลัพธ์ที่ได้คือเราสามารถเข้าถึง API ได้ พร้อมกับส่งกลับข้อมูลและ HTTP status code 200 ok
ดังรูปด้านบน
ส่วนวิธีการใช้งานแบบ Digest Authentication นั้น เท่าที่ลองทดสอบดู ยังไม่สามารถใช้งานได้อย่างสมบูรณ์
โดยสามารถใช้งานกรณีกำหนดให้เรียกใช้ผ่าน บราวเซอร์ได้ แต่ยังไม่สามารถเรียกใช้งานผ่าน Request API
จึงขอยังไม่ลงรายละเอียด หากมีอัพเดทจะนำมาเพิ่มหรือเขียนเป็นบทความต่อในภายหลัง
อย่างไรก็ดีถึงแม้การใช้งานแบบ Basic Authentication จะไม่มีความปลอดภัย สำหรับการจำกัดการเข้าถึงข้อมูล API
แต่ถ้า เว็บไซต์ของเรารองรับ SSL หรือที่เรียกผ่าน https การใช้งานแบบ Basic ก็ยังถือว่ามีความปลอดภัยแล้วในระดับหนึ่ง
นอกจากนั้น เรายังสามารถใช้งานร่วมกับ การกำหนดการจำกัดเฉพาะ IP ควบคู่ร่วมกันได้อีกด้วย จะขอกล่าวในหัวข้อตอนท้าย
การจำกัดการเข้าถึงข้อมูล API ด้วย session
ในกรณีที่เราต้องการเรียกใช้งานผ่าน Ajax โดยให้ฝั่งผู้ใช้ที่ร้องขอข้อมูล API ถูกจำกัดการเข้าใช้งานด้วย
ตัวแปร session ใน PHP เราสามารถกำหนดให้ RESTFul services ของเรา เลือกกำหนดตัวแปร session ที่ต้องการ
ใช้ เพื่อตรวจสอบก่อนเข้าใช้งานได้ ดังนี้
ให้ไปที่ไฟล์ rest.php ในโฟลเดอร์ apps > config
แล้วให้เปลี่ยนส่วนของการตั้งค่า $config['rest_auth']
เป็น
$config['rest_auth'] = 'session';
แล้วเปลี่ยนค่าในส่วนของ $config['auth_source']
ให้เป็นชื่อตัวแปร session ที่เราต้องการเช็ค สมมติ เช่น เมื่อมีการล็อกอินเข้าใช้งาน เราได้สร้างตัวแปร
session ที่ชื่อว่า ses_auth มีค่าเท่ากับ 1 เพิ่มเข้ามา เราก็ใช้ชื่อตัวแปร session นี้กำหนดค่าลงไปใน
$config['auth_source'] จะได้เป็นดังนี้
$config['auth_source'] = 'ses_auth';
ต่อไป เรามาลองสมมติการเรียกใช้งานผ่านหน้า home ด้วย ajax
หมายเหตุ:: เนื่องจากเนื้อหาเกี่ยวกับ codeigniter นี้เป็นการใช้รูปแบบที่ผู้เขียนกำหนดตั้งแต่ต้น
ดังนั้นโครงสร้างจึงเป็นไปตามตัวอย่างโค้ดที่แจกใน บทความเรื่อง
ภาคจบโปรเจ็ค การใช้งาน codeigniter และการกำหนด URL รองรับ SEO
https://www.ninenik.com/content.php?arti_id=683 via @ninenik
แต่ถ้าใครศึกษาเกี่ยวกับ Codeigniter มาพอสมควรแล้ว ก็สามารถที่จะนำไปใช้หรือทำความเข้าใจได้ไม่ยากนัก
ให้เราเปิดไฟล์ home.php ในโฟลเดอร์ apps > views > pages
แล้วแทรกโค้ดการเรียกข้อมูลจาก REST API ผ่าน คำสั่ง getJSON() ของ jQuery ดังนี้
<div class="container"> <h1><?=$title_h1?></h1> <br> <pre id="place_debug"> </pre> <script type="text/javascript"> $(function(){ $.getJSON("<?=base_url("/api/v1/provinces?fields=province_name")?>",function(data){ $("#place_debug").text(data); console.log(data); }); }); </script> </div>
หมายเหตุ: เนื้องจากโครงสร้างเว็บของเรามีการใช้งาน jQuery อยู่แล้วจึงสามารถเรียกใช้งานคำสั่ง jQuery ได้เลย
มาดูผลลัพธ์เมื่อหน้า home.php โหลดขึ้นมา ก็จะใช้งาน Ajax ผ่านคำสั่ง getJSON() ดังรูป
จะเห็นว่าในส่วนของ console จะมีการไป GET ค่าจาก API ที่เราระบุ แต่เกิด error ขึ้น และมี HTTP status code
เป็น 401 (Unauthorized) ทั้งนี้ก็เพราะ เราจำกัดการเข้าถึง API ด้วยตัวแปร session ที่ชื่อ ses_auth
เมื่อเราไม่มีค่าตัวแปรนี้มาก่อน ฝั่งของ REST API ก็จะไม่ส่งข้อมูลกลับมา
ทีนี้เราลองเพิ่มคำสั่ง สำหรับกำหนดตัวแปร session เข้าไปดู เป็นแบบนี้
<div class="container"> <h1><?=$title_h1?></h1> <br> <pre id="place_debug"> </pre> <?php $this->session->set_userdata('ses_auth',1); // สมมติกำหนดตัวแปร session ชื่อ ses_auth //if($this->session->has_userdata('ses_auth')){ // การเช็คว่ามีตัวแปรนี้หรือไม่ // $this->session->unset_userdata('ses_auth');// การล้างค่าตัวแปร //} ?> <script type="text/javascript"> $(function(){ $.getJSON("<?=base_url("/api/v1/provinces?fields=province_name")?>",function(data){ $("#place_debug").text(data); console.log(data); }); }); </script> </div>
สังเกตว่าเรามีการกำหนดตัวแปร session ชื่อ ses_auth มีค่าเท่ากับ 1 เข้าไปตรงๆ เพื่อทดสอบ
ที่นี้ลองรีเฟรสหน้า home นี้อีกครั้งดูการทำงาน จะได้ผลลัพธ์ดังรูป
จะเห็นว่ามีรายการ object ข้อมูล ถูกส่งกลับมา พร้อมนำไปใช้งานต่อไป ทั้งนี้ก็เพราะว่า ฝั่ง REST API มีการตรวจสอบ
ตัวแปร session ตามที่เรากำหนด และเมื่อมีค่าตัวแปร ก็สามารถเข้าถึงข้อมูล API ได้นั่นเอง
การจำกัดการเข้าถึงข้อมูล API ด้วย IP address
ถึงแม้การจำกัดการเข้าถึงข้อมูล API ด้วยวิธีข้างต้นจะมีความปลอดภัยในระบบดับหนึ่งแล้ว เรายังสามารถกำหนด
การจำกัดการเข้าถึงเพิ่มเติมโดยการใช้งาน IP white-list และ IP Blacklist ได้อีกด้วย ซึ่งจะช่วยเพิ่มระดับ
ความปลอดภัยของข้อมูล API เพิ่มขึ้นอีก
ความหมายก็ตามชื่อที่เรียกเลย
IP white-list ก็คือ กำหนด IP address ที่สามารถเข้าถึง API ได้
IP Blacklist ก็คือ กำหนด IP address ที่ต้องการป้องกันไม่ให้เข้าถึง API
การกำหนด REST IP white-list ให้เรากำหนดค่าในไฟล์ rest.php ในโฟลเดอร์ apps > config
ดูในส่วนของค่า
$config['rest_ip_whitelist_enabled'] = FALSE; // ค่าเริ่มต้นเป็น FALSE ถ้าต้องการใช้งานให้กำหนดเป็น TRUE
กำหนดให้เป็น TRUE
$config['rest_ip_whitelist_enabled'] = TRUE; // ซึ่งหมายถึงเปิดใช้งานการจำกัด้วย IP white-list
หลังจากนั้นเราก็สามารถไประบุ IP address ในส่วนของค่า
$config['rest_ip_whitelist'] = '';
ตัวอย่างเช่น
$config['rest_ip_whitelist'] = '123.456.789.0, 987.654.32.1';
เป็นการกำหนด IP สองค่าเข้าไปใน white-list คั่นแต่ละค่าด้วย , (comma)
เรามาลองรันหน้า home ดูผลลัพธ์ที่ได้อีกครั้ง ก็จะพบว่า ไม่สามารถเรียกดูข้อมูลได้แล้ว ถึงแม้จะผ่าน
ด่านแรก คือมีตัวแปร session ตามที่กำหนด แต่ก็มาติดด่านที่สองคือ IP ไม่ตรงกับที่อนุญาตให้เข้าถึง
หลักการทำงานก็ประมาณนี้ การกำหนด IP white-list เหมาะสำหรับกรณีที่ API นี้ให้สามารถเรียกใช้งานผ่านเว็บไซต์
ของเราเว็บไซต์เดียว โดยเว็บไซต์ของเราต้องมี IP แบบ static ด้วย หรือก็คือมี IP ที่ไม่ซ้ำกับคนอื่น
สำหรับหลักกากำหนดใน REST IP Blacklist ก็จะทำในลักษณะคล้ายกัน ในความหมายตรงกันข้ามคือ
IP ที่กำหนด คือ IP ที่ไม่สามารถเข้าถึง API ได้ กำหนดในไฟล์ rest.php ในโฟลเดอร์ apps > config
โดยเปิดหรือปิดใช้งานในส่วนของการกำหนดค่า
$config['rest_ip_blacklist_enabled'] = FALSE;
และกำหนด IP address ในส่วนของการกำหนดค่า
$config['rest_ip_blacklist'] = '';
สำหรับเนื้อหาเกี่ยวกับการจำกัดการเข้าถึงข้อมูล API ในเบี้องต้นก็มีเพียงเท่านี้ อย่างไรก็ตาม ในส่วนของ RESTFul
services ยังรองรับการกำหนด API key ไว้นำมาเป็นบทความเพิ่มเติมในโอกาสต่อๆ ไป