GHB Security
การทำ Pentest ของระบบที่เป็น Springboot ที่การทดสอบอย่างไร เพื่อป้องกันช่องโหว่ของ API
การทำ Pentest (Penetration Testing) ของระบบที่ใช้ Spring Boot เพื่อป้องกันช่องโหว่ของ API ควรมีขั้นตอนดังนี้:
- การเตรียมพร้อม:
- ทำความเข้าใจกับระบบ: รวบรวมข้อมูลเกี่ยวกับแอปพลิเคชัน, API, และส่วนประกอบที่เกี่ยวข้อง เช่น URL, endpoint, วิธีการ authentication, และ authorization
- กำหนดขอบเขตการทดสอบ: ระบุขอบเขตที่แน่นอนของการทดสอบ เช่น ส่วนไหนที่สามารถทดสอบได้ และส่วนไหนที่ห้ามทดสอบ
- รับอนุญาต: ตรวจสอบให้แน่ใจว่าได้รับอนุญาตจากผู้ดูแลระบบหรือเจ้าของระบบก่อนทำการทดสอบ
- การทดสอบช่องโหว่ทั่วไปของ API:
- การตรวจสอบการ authentication และ authorization: ตรวจสอบว่า API มีการป้องกันที่เหมาะสมในการตรวจสอบตัวตน (authentication) และสิทธิ์การเข้าถึง (authorization)
- การทดสอบ SQL Injection: ตรวจสอบว่า API มีการป้องกันการโจมตีด้วย SQL Injection หรือไม่ โดยการป้อนข้อมูลที่เป็นอันตรายเข้าไปใน parameter ที่คาดว่าน่าจะมีการ query ข้อมูลใน database
- การทดสอบ XSS (Cross-Site Scripting): ตรวจสอบว่า API มีการป้องกันการโจมตีด้วย XSS หรือไม่ โดยการป้อนข้อมูลที่เป็นอันตรายเข้าไปใน parameter ที่จะถูกแสดงผลบนหน้าเว็บ
- การทดสอบ CSRF (Cross-Site Request Forgery): ตรวจสอบว่า API มีการป้องกันการโจมตีด้วย CSRF หรือไม่ โดยการส่ง request ที่เป็นอันตรายไปยัง API
- การทดสอบช่องโหว่เฉพาะใน Spring Boot:
- การตรวจสอบการตั้งค่าความปลอดภัยของ Spring Security: ตรวจสอบว่ามีการตั้งค่า Spring Security อย่างถูกต้องเพื่อป้องกันช่องโหว่ เช่น การใช้ JWT token หรือ OAuth2
- การทดสอบการจัดการ session: ตรวจสอบว่า session ที่ใช้งานใน Spring Boot มีความปลอดภัย เช่น การป้องกัน session fixation
- การทดสอบการจัดการ exception: ตรวจสอบว่าแอปพลิเคชันมีการจัดการ exception อย่างเหมาะสม เพื่อไม่ให้ข้อมูลที่เป็นอันตรายหรือข้อมูลที่เป็นความลับถูกเปิดเผย
- การใช้เครื่องมือทดสอบ:
- ใช้เครื่องมือเช่น OWASP ZAP หรือ Burp Suite: เครื่องมือเหล่านี้สามารถช่วยในการตรวจหาช่องโหว่ของ API โดยอัตโนมัติ
- ใช้เครื่องมือ fuzzing: เพื่อส่งข้อมูลที่หลากหลายและสุ่มไปยัง API เพื่อหาช่องโหว่
- การวิเคราะห์ผลการทดสอบ:
- ตรวจสอบผลลัพธ์จากการทดสอบ: วิเคราะห์ผลการทดสอบจากเครื่องมือและตรวจสอบว่าช่องโหว่ที่พบมีผลกระทบอย่างไรบ้าง
- จัดลำดับความสำคัญ: จัดลำดับความสำคัญในการแก้ไขช่องโหว่ตามระดับความเสี่ยง
- การแก้ไขและปรับปรุง:
- การแก้ไขช่องโหว่: ทำการแก้ไขช่องโหว่ที่พบในการทดสอบ
- การทดสอบซ้ำ: หลังจากแก้ไขแล้ว ควรทำการทดสอบซ้ำเพื่อยืนยันว่าช่องโหว่ถูกแก้ไขเรียบร้อยแล้ว
- การปรับปรุงการตั้งค่าและการพัฒนา: ปรับปรุงการตั้งค่าและแนวทางการพัฒนาเพื่อป้องกันไม่ให้เกิดช่องโหว่ในอนาคต
การทำ Pentest เป็นกระบวนการที่ต่อเนื่องและควรทำอย่างสม่ำเสมอเพื่อให้แน่ใจว่าระบบของคุณมีความปลอดภัยจากช่องโหว่ต่าง ๆ อยู่เสมอ
ใน Java Spring-boot มีวิธีรัน Command เพื่อสรุป Route API ทั้งหมดได้หรือไม่
ใน Java Spring Boot คุณสามารถใช้คำสั่งเพื่อสรุป Route API ทั้งหมดในแอปพลิเคชันได้โดยการใช้งาน Spring Boot Actuator หรือเขียนโค้ดเฉพาะเพื่อดึงข้อมูลจาก RequestMappingHandlerMapping
ใน Spring MVC
วิธีที่ 1: ใช้ Spring Boot Actuator
- เพิ่ม Dependency ใน
pom.xml
: - เปิดใช้งาน Actuator Endpoint ใน
application.properties
: - เรียกดู API Endpoint:
- รันแอปพลิเคชัน Spring Boot
- เปิดเบราว์เซอร์หรือใช้เครื่องมืออย่าง
curl
เพื่อเรียกดูที่ URL:http://localhost:8080/actuator/mappings
ตัวอย่าง:
วิธีที่ 2: เขียนโค้ดเฉพาะเพื่อดึง Route API
- สร้าง Bean ที่จะดึงข้อมูลจาก
RequestMappingHandlerMapping
: - รันแอปพลิเคชัน Spring Boot: เมื่อแอปพลิเคชันรัน, Bean ที่สร้างขึ้นจะพิมพ์รายการของ API Endpoints ใน console
การใช้โค้ดเหล่านี้จะช่วยให้คุณสามารถดึงข้อมูลและสรุป Route API ทั้งหมดในแอปพลิเคชัน Spring Boot ได้ง่าย ๆ
จากภาพที่แสดง HTTP Status 401 - Unauthorized หมายความว่าคุณต้องทำการ authentication (การยืนยันตัวตน) เพื่อเข้าถึง endpoint ของ Spring Boot Actuator นี่คือวิธีการแก้ไข:
วิธีการเปิดใช้งานการ authentication สำหรับ Actuator
- เพิ่ม dependency สำหรับ Spring Security ใน
pom.xml
: - เพิ่มการตั้งค่าการรักษาความปลอดภัยใน
application.properties
: - สร้าง Security Configuration Class: สร้างไฟล์ใหม่ เช่น
SecurityConfig.java
ใน package ของคุณ และกำหนดค่า Spring Security: - รันแอปพลิเคชัน: เมื่อรันแอปพลิเคชันใหม่ คุณสามารถเข้าถึง actuator endpoint โดยใช้ข้อมูลการเข้าสู่ระบบที่กำหนดใน
application.properties
(ในตัวอย่างคือadmin
และadmin123
) - ลองเข้าถึง URL:
- เปิดเบราว์เซอร์อีกครั้ง และเข้าไปที่
http://localhost:8081/actuator/mappings
- ใช้ข้อมูลการเข้าสู่ระบบที่ตั้งไว้ (
admin
และadmin123
) เพื่อเข้าถึงข้อมูล
- เปิดเบราว์เซอร์อีกครั้ง และเข้าไปที่
เพียงเท่านี้คุณก็จะสามารถดู Route API ทั้งหมดของแอปพลิเคชันได้แล้ว
กรณี Login ผ่าน Return Token { "response_code": "200", "message": "Valid user", "username": "SCMS001", "staffName": "ฟร้อง", "userId": 219, "userIdReference": null, "pinCode": null, "token": "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJTQ01TMDAxIiwicm9sZSI6bnVsbCwiY3JlYXRlZCI6MTcyMTk2OTI4MzMwOCwic3RhZmZuYW1lIjoi4Lif4Lij4LmJ4Lit4LiHIiwiaWQiOjIxOSwiZXhwIjoxNzIyMDA1MjgzfQ.dlZuFaPA6tfgBh2x8X9p7vX6xlhZ8wIybxFzGJ1vB0mnaOeOmv0mpGWNMESK_elCnW2qqdgdI9EKeo1hEsg5rg", "org_id": null, "org_br_id": null, "dept_id": null, "cust_corp_id": null, "cust_corp_br_id": null, "cust_corp_dept_id": null, "online_status": "online", "branch_name_th": null, "branch_id": null } กรณี Login ไม่ผ่าน Return { "response_code": "400", "message": "User not found", "username": null, "staffName": null, "userId": null, "userIdReference": null, "pinCode": null, "token": null, "org_id": null, "org_br_id": null, "dept_id": null, "cust_corp_id": null, "cust_corp_br_id": null, "cust_corp_dept_id": null, "online_status": null, "branch_name_th": null, "branch_id": null } แบบนี้มีช่องโหว่หรือไม่
จากข้อมูลที่ให้มา เกี่ยวกับการ Login และการส่งคืน Token เมื่อผู้ใช้ล็อกอินสำเร็จ หรือการตอบกลับเมื่อผู้ใช้ไม่สามารถล็อกอินได้ สิ่งสำคัญในการพิจารณาว่ามีช่องโหว่หรือไม่คือการตรวจสอบขั้นตอนการจัดการข้อมูลต่างๆ ดังนี้:
การตรวจสอบความปลอดภัยของการ Login และการจัดการ Token
- การใช้ HTTPS:
- ตรวจสอบว่า API ใช้ HTTPS ในการรับส่งข้อมูล เพื่อป้องกันการดักจับข้อมูลระหว่างการรับส่ง
- การจัดการ Token:
- ตรวจสอบว่า Token ที่สร้างขึ้นมีความปลอดภัย (เช่น ใช้ JWT ที่เข้ารหัสด้วย secret key ที่ปลอดภัย)
- Token ควรมีเวลาในการหมดอายุ (expiration time) เพื่อป้องกันการใช้งานที่ไม่ถูกต้อง
- การป้องกัน Brute Force Attack:
- ควรมีการจำกัดจำนวนครั้งในการพยายามเข้าสู่ระบบ เพื่อป้องกันการโจมตีด้วยการลองรหัสผ่านหลายๆ ครั้ง
- อาจเพิ่มการตรวจสอบ Captcha หลังจากความพยายามเข้าสู่ระบบหลายครั้งไม่สำเร็จ
- การเก็บข้อมูลที่จำเป็น:
- ตรวจสอบว่าข้อมูลที่เก็บใน Token หรือที่ส่งกลับมีเฉพาะข้อมูลที่จำเป็น ไม่เก็บข้อมูลที่เป็นความลับหรือไม่จำเป็น
- การตอบกลับเมื่อผู้ใช้ไม่สามารถล็อกอินได้ ควรให้ข้อมูลที่ไม่เป็นอันตราย เช่น "User not found" โดยไม่บอกรายละเอียดเพิ่มเติม
- การป้องกัน CSRF:
- ใช้การตรวจสอบ CSRF เพื่อป้องกันการโจมตีจากการเรียกใช้ API โดยไม่ตั้งใจจากเว็บอื่น
- การจัดการ Error Response:
- ตรวจสอบว่าข้อความ error ที่ส่งกลับไม่ให้ข้อมูลที่เป็นอันตราย เช่น การเปิดเผยโครงสร้างของฐานข้อมูล หรือรายละเอียดอื่นๆ ที่อาจใช้ในการโจมตี
ตัวอย่างเพิ่มเติมของโค้ดเพื่อเพิ่มความปลอดภัย
- การตรวจสอบ Token ใน Spring Boot Security:
- การตั้งค่า Token Expiration:
สรุป
จากข้อมูลที่ให้มา การทำงานของ API ยังมีบางจุดที่ควรตรวจสอบและปรับปรุงเพื่อความปลอดภัย เช่น การใช้ HTTPS, การจัดการ Token, และการป้องกันการโจมตี Brute Force และ CSRF การตรวจสอบเหล่านี้จะช่วยให้ API ของคุณมีความปลอดภัยมากขึ้น
@PostMapping("/auth/genesys/signin") public ResponseEntity<Object> getAuthenticationGenesys(@RequestBody GenesysAuthenticationBean body, HttpServletRequest request) throws AuthenticationException { String email = body.getEmail(); JwtUser userDetails; String headerApikey = request.getHeader("api_key"); if (!apiKey.equals(headerApikey)) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized"); } try { UserInfoIDSBean userSystem = userRepository.findUserProfileByEmail(email); if (Optional.ofNullable(userSystem).isPresent()) { userDetails = (JwtUser) userDetailsService.loadUserByUsername(userSystem.getUsername()); final String token = jwtTokenUtil.generateToken(userDetails); if (updateTokenExpire(userSystem.getUsername(), token)) { userRepository.lastLoginDatetime(userSystem.getUsername()); return ResponseEntity.ok(code200Response(userSystem.getUsername(), token)); } else { return ResponseEntity.ok(code400Response()); } } else { return ResponseEntity.ok(code400Response()); } } catch (Exception ex) { logger.info("Got an exception. {}", ex.getMessage()); return ResponseEntity.ok(code400Response()); } } --- Bean --- package th.co.scms.allway.api.bean; import lombok.Data; @Data public class GenesysAuthenticationBean { private String email; }
จากโค้ดที่คุณให้มา การทำงานในการตรวจสอบการเข้าสู่ระบบและการจัดการ token นั้นมีหลายจุดที่ควรพิจารณาเพื่อเพิ่มความปลอดภัยและประสิทธิภาพของ API ดังนี้:
จุดที่ควรปรับปรุงเพื่อความปลอดภัย
- การตรวจสอบ API Key:
- ตรวจสอบว่า
apiKey
มีการตั้งค่าอย่างปลอดภัย และไม่ถูกเปิดเผยในโค้ด - API Key ควรได้รับการเก็บในที่ที่ปลอดภัย เช่น environment variables หรือ configuration file ที่เข้ารหัส
- ตรวจสอบว่า
- การจัดการ Exceptions:
- ไม่ควรใช้
catch (Exception ex)
เพราะจะทำให้การจับข้อผิดพลาดไม่ชัดเจน ควรจับข้อผิดพลาดที่เฉพาะเจาะจง เช่นUsernameNotFoundException
,BadCredentialsException
เป็นต้น
- ไม่ควรใช้
- การจัดการ Token:
- ควรตรวจสอบว่า token ที่สร้างขึ้นมีการเข้ารหัสที่ปลอดภัย และมีเวลาหมดอายุ (expiration time) ที่เหมาะสม
- การป้องกัน Brute Force Attack:
- ควรมีการจำกัดจำนวนครั้งในการพยายามเข้าสู่ระบบ เช่น ล็อคบัญชีผู้ใช้ชั่วคราวหากพยายามเข้าสู่ระบบหลายครั้งไม่สำเร็จ
ตัวอย่างโค้ดปรับปรุง
สรุป
- ตรวจสอบการตั้งค่า
apiKey
ให้ปลอดภัย - จัดการ exception ให้เฉพาะเจาะจงและเหมาะสม
- เพิ่มการจัดการ token ที่มีเวลาหมดอายุ
- เพิ่มการป้องกัน Brute Force Attack
การปรับปรุงเหล่านี้จะช่วยเพิ่มความปลอดภัยและประสิทธิภาพของระบบการล็อกอินใน Spring Boot API ของคุณ