Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> สมาร์ทโฟน >> iPhone

การพัฒนา iOS อย่างปลอดภัยใน Swift:หลีกเลี่ยงข้อผิดพลาดทั่วไปและเสริมความแข็งแกร่งให้กับแอปของคุณ

การพัฒนา iOS อย่างปลอดภัยใน Swift:หลีกเลี่ยงข้อผิดพลาดทั่วไปและเสริมความแข็งแกร่งให้กับแอปของคุณ

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

ดังนั้น หากคุณเป็นนักพัฒนา iOS คุณควรเรียนรู้ที่จะจัดลำดับความสำคัญด้านความปลอดภัยในทุกขั้นตอนของการพัฒนาแอป

Swift ซึ่งเป็นภาษาการเขียนโปรแกรมสมัยใหม่ของ Apple นำเสนอเครื่องมือและเฟรมเวิร์กมากมายที่ทำให้การพัฒนาง่ายขึ้นพร้อมทั้งเพิ่มความปลอดภัย แต่เมื่อใช้อย่างถูกต้องเท่านั้น

บทความนี้จะสำรวจข้อผิดพลาดด้านความปลอดภัยทั่วไป 10 ประการในแอพ iOS ที่ใช้ Swift และเสนอกลยุทธ์ที่ใช้งานได้จริงเพื่อบรรเทาผลกระทบ

ข้อกำหนดเบื้องต้น

ก่อนที่จะดำน้ำ คุณจะต้องมีสิ่งต่อไปนี้:

  • ความรู้ด้านการทำงานของ Swift และการพัฒนา iOS

  • เข้าถึง Xcode

  • ความเข้าใจพื้นฐานเกี่ยวกับวิธีที่แอพ iOS สื่อสารกับเซิร์ฟเวอร์

  • ความคุ้นเคยกับพื้นฐานเทอร์มินัล/บรรทัดคำสั่ง

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

สิ่งที่เราจะกล่าวถึง:

  • กับดักความปลอดภัยที่พบบ่อยที่สุดในแอพพลิเคชั่น Swift iOS คืออะไร
    • 1. การจัดเก็บข้อมูลที่ไม่ปลอดภัย
    • 2. การสื่อสารผ่านเครือข่ายที่อ่อนแอ
    • 3. การตรวจสอบอินพุตที่ไม่เหมาะสม
    • 4. ความลับการเข้ารหัส
    • 5. การรับรองความถูกต้องและการอนุญาตไม่เพียงพอ
    • 6. การบันทึกที่ไม่ปลอดภัยและการจัดการข้อผิดพลาด
    • 7. ละเว้นการทำให้โค้ดสับสนและวิศวกรรมย้อนกลับ
    • 8. ไลบรารีของบุคคลที่สามที่ไม่ปลอดภัย
    • 9. การรับรองความถูกต้องด้วยไบโอเมตริกซ์และหลายปัจจัยไม่เพียงพอ
    • 10. ไม่สนใจการทดสอบความปลอดภัยเป็นระยะ

กับดักความปลอดภัยที่พบบ่อยที่สุดในแอพพลิเคชั่น Swift iOS คืออะไร

Swift และ iOS นำเสนอฟีเจอร์ความปลอดภัยที่แข็งแกร่ง แต่ข้อผิดพลาดยังคงเกิดขึ้น ต่อไปนี้เป็นกับดักที่พบบ่อยที่สุดและวิธีแก้ไข:

1. การจัดเก็บข้อมูลที่ไม่ปลอดภัย

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

แม้ว่า UserDefaults จะสะดวกสำหรับข้อมูลจำนวนเล็กน้อย แต่ก็ไม่ปลอดภัยสำหรับข้อมูลที่ละเอียดอ่อน เนื่องจากผู้โจมตีเข้าถึงได้ง่ายมากหากอุปกรณ์ถูกบุกรุก

วิธีการแก้ไข:

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

คุณสามารถจัดเก็บข้อมูลประจำตัวได้อย่างปลอดภัยโดยใช้ไลบรารีใน Swift เช่น KeychainAccess หรือฟังก์ชัน SecItemAdd และ SecItemCopyMatching ในตัว

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

do {
try keychain.set("userPassword123", key: "userPassword")
} catch {
 print("Error saving to Keychain: \(error)")
}

เบื้องหลัง นี่คือสิ่งที่เกิดขึ้นเมื่อคุณโทรหา 08 ภายในคลาส KeychainManager ที่ใช้เฟรมเวิร์กความปลอดภัยดั้งเดิมของ Apple สำหรับการจัดเก็บ:

import Security
class KeychainManager {
 func set(_ value: String, key: String) throws {
 // 1. Convert string to Data
 guard let data = value.data(using: .utf8) else {
 throw NSError(domain: "KeychainManager", code: -1)
 }
 // 2. Build the query dictionary
 let query: [String: Any] = [
 // Store as password
 kSecClass as String: kSecClassGenericPassword,
 // Your app's bundle identifier
 kSecAttrService as String: "com.yourapp.keychain",
 // "userPassword"
 kSecAttrAccount as String: key,
 // "userPassword123" encrypted
 kSecValueData as String: data,
 kSecAttrAccessible as String: kSecAttrAccessibleAfterFirstUnlock
 ]
 // 3. Save to keychain (iOS encrypts it automatically)
 let status = SecItemAdd(query as CFDictionary, nil)
 // 4. Check if successful
 guard status == errSecSuccess else {
 throw NSError(domain: "KeychainManager", code: Int(status))
 }
 }
}

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

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

2. การสื่อสารผ่านเครือข่ายที่อ่อนแอ

การส่งข้อมูลที่มีความละเอียดอ่อนผ่านเครือข่ายเป็นอีกพื้นที่หนึ่งที่เสี่ยงต่อช่องโหว่ การใช้การเชื่อมต่อ HTTP ที่ไม่ได้เข้ารหัสจะทำให้แอปของคุณถูกโจมตีจากคนกลาง (MITM) ทำให้ผู้โจมตีสามารถสกัดกั้นและแก้ไขข้อมูลระหว่างทางได้

ปัญหา :เมื่อข้อมูลเดินทางระหว่างแอปและเซิร์ฟเวอร์ของคุณผ่านการเชื่อมต่อที่ไม่ปลอดภัย ผู้โจมตีบนเครือข่ายเดียวกัน (เช่น Wi-Fi สาธารณะ) จะสามารถ:

  • อ่านข้อมูลที่ละเอียดอ่อน (รหัสผ่าน ข้อมูลส่วนบุคคล รายละเอียดการชำระเงิน)

  • แก้ไขคำขอและการตอบกลับ

  • ปลอมตัวเป็นเซิร์ฟเวอร์ที่ถูกต้องตามกฎหมายของคุณ

วิธีการแก้ไข:

1. ใช้ HTTPS เสมอ
HTTPS เข้ารหัสข้อมูลทั้งหมดระหว่างการส่ง ทำให้ผู้โจมตีไม่สามารถอ่านได้ App Transport Security (ATS) ของ iOS บังคับใช้สิ่งนี้โดยการบล็อกการเชื่อมต่อ HTTP ที่ไม่ปลอดภัยตามค่าเริ่มต้น:

// ❌ INSECURE - HTTP connection (blocked by ATS by default)
let url = URL(string: "http://api.example.com/login")
// ✅ SECURE - HTTPS connection
let url = URL(string: "https://api.example.com/login")

คุณจะต้องหลีกเลี่ยงการเพิ่มข้อยกเว้น ATS ให้กับ Info.plist ของคุณ เว้นแต่จะจำเป็นจริงๆ หาก API ของบุคคลที่สามรองรับเฉพาะ HTTP โปรดติดต่อพวกเขาเพื่ออัปเกรดหรือค้นหาทางเลือกที่ปลอดภัยกว่านี้

<แข็งแกร่ง>2. ใช้การปักหมุดใบรับรอง (การป้องกันขั้นสูง)

แม้ว่าจะใช้ HTTPS แอปของคุณก็อาจยังเสี่ยงต่อการโจมตี MITM ที่ซับซ้อน ผู้โจมตีสามารถติดตั้งใบรับรองที่ฉ้อโกงบนอุปกรณ์ของผู้ใช้ (ผ่านมัลแวร์หรือวิศวกรรมสังคม) เป็นต้น และสกัดกั้นการรับส่งข้อมูล HTTPS ที่ดูเหมือนว่าถูกต้อง อุปกรณ์จะเชื่อถือใบรับรองปลอมของผู้โจมตี ช่วยให้พวกเขาสามารถถอดรหัสและอ่านการสื่อสารที่ "ปลอดภัย" ได้

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

วิธีการทำงานของการปักหมุดใบรับรอง:

แอปของคุณจัดเก็บใบรับรองที่คาดหวัง (หรือแฮชคีย์สาธารณะ) และตรวจสอบความถูกต้องระหว่างการเชื่อมต่อแต่ละครั้ง:

class SecureNetworkManager: NSObject, URLSessionDelegate {
 // Store your server's certificate hash
 // Get this by running: openssl x509 -in certificate.crt -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | base64
 private let expectedPublicKeyHash = "YOUR_CERTIFICATE_HASH_HERE"
 func urlSession(
 _ session: URLSession,
 didReceive challenge: URLAuthenticationChallenge,
 completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void
 ) {
 // Step 1: Check if this is a server trust challenge (certificate validation)
 guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
 let serverTrust = challenge.protectionSpace.serverTrust
 else {
 // Not a certificate challenge; use default handling
 completionHandler(.performDefaultHandling, nil)
 return
 }
 // Step 2: Validate that the server's certificate matches our pinned certificate
 if isValidServerTrust(serverTrust) {
 // Certificate matches - proceed with the connection
 completionHandler(.useCredential, URLCredential(trust: serverTrust))
 } else {
 // Certificate doesn't match - reject the connection to prevent MITM attack
 completionHandler(.cancelAuthenticationChallenge, nil)
 }
 }
 // Validates the server's certificate against our pinned hash
 private func isValidServerTrust(_ serverTrust: SecTrust) -> Bool {
 // Extract the server's certificate
 guard let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) else {
 return false
 }
 // Get the public key from the certificate
 let serverPublicKey = SecCertificateCopyKey(serverCertificate)
 guard let publicKey = serverPublicKey else {
 return false
 }
 // Convert the public key to data and hash it
 var error: Unmanaged<CFError>?
 guard let publicKeyData = SecKeyCopyExternalRepresentation(publicKey, &error) as Data? else {
 return false
 }
 // Hash the public key using SHA-256
 let publicKeyHash = SHA256.hash(data: publicKeyData)
 let publicKeyHashString = Data(publicKeyHash).base64EncodedString()
 // Compare with our expected hash
 return publicKeyHashString == expectedPublicKeyHash
 }
}

รหัสนี้ทำอะไรทีละขั้นตอน:

  1. 12 – วิธีการนี้จะถูกเรียกเมื่อใดก็ตามที่แอปของคุณทำการเชื่อมต่อ HTTPS iOS ถามว่า:"ฉันควรเชื่อถือใบรับรองของเซิร์ฟเวอร์นี้หรือไม่"

  2. ตรวจสอบวิธีการตรวจสอบสิทธิ์ – เราตรวจสอบยืนยันว่านี่คือความท้าทายด้านความน่าเชื่อถือของเซิร์ฟเวอร์ (การตรวจสอบใบรับรอง) ไม่ใช่การตรวจสอบสิทธิ์ประเภทอื่น

  3. ตรวจสอบใบรับรอง – เราเรียกว่า 26 ซึ่ง:

    • แยกใบรับรองของเซิร์ฟเวอร์ออกจากการเชื่อมต่อ

    • รับรหัสสาธารณะจากใบรับรองนั้น

    • แฮชกุญแจสาธารณะโดยใช้ SHA-256

    • เปรียบเทียบแฮชกับแฮชที่คาดหวังที่เก็บไว้ของเรา

  1. ตัดสินใจ:
  • หากแฮชตรงกัน แสดงว่าเซิร์ฟเวอร์นั้นถูกต้องตามกฎหมาย ดำเนินการต่อด้วย 31 .

  • หากแฮชไม่ตรงกัน แสดงว่าอาจถูกโจมตีจาก MITM ยกเลิกด้วย 42 .

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

<แข็งแกร่ง>3. การป้องกันเพิ่มเติม:แนะนำ VPN บน Wi-Fi สาธารณะ

คุณยังแนะนำให้ผู้ใช้เชื่อมต่อผ่าน VPN เมื่อใช้ Wi-Fi สาธารณะเพื่อเพิ่มระดับความปลอดภัย และให้คำแนะนำเกี่ยวกับวิธีใช้ VPN อย่างมีประสิทธิภาพเพื่อรักษาข้อมูลให้ปลอดภัย

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

3. การตรวจสอบอินพุตที่ไม่เหมาะสม

นักพัฒนาบางรายละเลยการตรวจสอบอินพุตที่ถูกต้อง ซึ่งนำไปสู่ช่องโหว่จำนวนหนึ่ง รวมถึงการแทรก SQL, การเรียกใช้โค้ดจากระยะไกล และความเสียหายของข้อมูล

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

วิธีการแก้ไข:

การตรวจสอบอินพุตเป็นด่านแรกในการป้องกันข้อมูลที่เป็นอันตราย ต่อไปนี้เป็นวิธีปกป้องแอปพลิเคชัน iOS ของคุณ:

1. ตรวจสอบการป้อนข้อมูลของผู้ใช้ด้วยรูปแบบ

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

func isValidEmail(_ email: String) -> Bool {
 let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
 let emailPredicate = NSPredicate(format: "SELF MATCHES %@", emailRegex)
 return emailPredicate.evaluate(with: email)
}
// Only accept properly formatted data
guard isValidEmail(userEmail) else {
 // Reject invalid input
 return
}

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

<แข็งแกร่ง>2. ฆ่าเชื้อการตอบสนองของ API

อย่าเชื่อถือข้อมูลภายนอก ตรวจสอบและฆ่าเชื้อการตอบสนองของ API ก่อนใช้งานเสมอ:

if let userAge = apiResponse["age"] as? Int,
 userAge >= 0 && userAge <= 150 {
 // Safe to use
 user.age = userAge
} else {
 // Handle invalid data appropriately
 throw ValidationError.invalidAge
}

<แข็งแกร่ง>3. ใช้การสืบค้นแบบกำหนดพารามิเตอร์ (สำคัญที่สุด)

ข้อผิดพลาดที่อันตรายที่สุดคือการสร้างแบบสอบถามฐานข้อมูลผ่านการต่อสตริง พิจารณาโค้ดที่มีช่องโหว่นี้:

// ❌ NEVER DO THIS - Vulnerable to SQL Injection
let username = userInput // Could be: "admin' OR '1'='1"
let query = "SELECT * FROM users WHERE username = '\(username)'"
database.execute(query)

หากผู้ใช้ที่เป็นอันตรายป้อน admin' หรือ '1'='1 เป็นชื่อผู้ใช้ ข้อความค้นหาจะกลายเป็น:

SELECT * FROM users WHERE username = 'admin' OR '1'='1'

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

// ✅ SAFE - Using parameterized queries
let query = "SELECT * FROM users WHERE username = ?"
database.execute(query, withArgumentsIn: [username])

ในแนวทางนี้ 51 เป็นตัวยึดตำแหน่งที่ฐานข้อมูลถือเป็นพารามิเตอร์ ไม่ใช่ส่วนหนึ่งของคำสั่ง SQL ค่าชื่อผู้ใช้จะถูกส่งแยกกันใน 64 อาร์เรย์.

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

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

4. ความลับการเข้ารหัส

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

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

ปัญหา – ความลับแบบฮาร์ดโค้ด:

// NEVER DO THIS
class APIClient {
 private let apiKey = "1234567890abcdef"
 private let secretToken = "sk_live_51H..."
 func makeRequest() {
 // These secrets are embedded in your binary
 let headers = ["Authorization": "Bearer \(apiKey)"]
 }
}

วิธีแก้ไข:

อย่าจัดเก็บข้อมูลประจำตัวที่ละเอียดอ่อนไว้ในโค้ดของคุณโดยตรง นี่คือทางเลือกอื่นที่ปลอดภัย:

โซลูชันที่ 1:ดึงข้อมูลลับจากแบ็กเอนด์ที่รันไทม์

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

class APIClient {
 private var sessionToken: String?
 // User logs in and receives a temporary session token
 func authenticateUser(email: String, password: String) async throws {
 let response = try await backend.login(email: email, password: password)
 // Store only a temporary, user-specific session token
 self.sessionToken = response.sessionToken
 }
 // Backend handles the actual API calls with the real API key
 func fetchUserData() async throws -> UserData {
 guard let token = sessionToken else {
 throw AuthError.notAuthenticated
 }
 // Your backend receives this request, validates the session token,
 // then uses its own API keys to fetch data from third-party services
 return try await backend.getUserData(sessionToken: token)
 }
}

วิธีการทำงาน:

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

โซลูชันที่ 2:ตัวแปรสภาพแวดล้อมหรือไฟล์กำหนดค่า (การพัฒนาเท่านั้น)

สำหรับสภาพแวดล้อมการพัฒนา ให้ใช้ไฟล์ .xcconfig ที่ไม่รวมอยู่ในการควบคุมเวอร์ชัน:

// Secrets.xcconfig (add to .gitignore!)
API_KEY = your_dev_api_key_here
API_SECRET = your_dev_secret_here
// Access in your code through Info.plist
class Config {
 static let apiKey: String = {
 guard let key = Bundle.main.object(forInfoDictionaryKey: "API_KEY") as? String else {
 fatalError("API_KEY not found in configuration")
 }
 return key
 }()
}

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

5. การรับรองความถูกต้องและการอนุญาตไม่เพียงพอ

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

วิธีการแก้ไข:

  • ทำการรับรองความถูกต้องและการอนุญาตบนฝั่งเซิร์ฟเวอร์แทนฝั่งไคลเอ็นต์

  • ใช้ JWT (JSON Web Tokens) หรือ OAuth 2.0 สำหรับการเข้าสู่ระบบของผู้ใช้ที่ได้รับการตรวจสอบสิทธิ์

  • จำเป็นต้องใช้ตรรกะการหมดอายุและรีเฟรชโทเค็นเพื่อลดโอกาสที่โทเค็นจะถูกขโมย

ตัวอย่าง:การส่ง JWT อย่างปลอดภัย:

let request = URLRequest(url: apiURL)
request.setValue("Bearer \(jwtToken)", forHTTPHeaderField: "Authorization")

6. การบันทึกที่ไม่ปลอดภัยและการจัดการข้อผิดพลาด

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

วิธีการแก้ไข:

  • บันทึกข้อมูลที่ละเอียดอ่อนอย่างระมัดระวัง

  • ใช้การจัดการข้อผิดพลาดที่มีการควบคุมและให้ข้อมูลจำนวนขั้นต่ำในข้อความที่ผู้ใช้นำเสนอ

  • ใช้ไลบรารีการบันทึกที่ปลอดภัยซึ่งปกปิดหรือเข้ารหัสข้อมูลส่วนบุคคล

do {
 try someRiskyOperation()
} catch {
 // Log error securely
 Logger.log("Operation failed: \(error.localizedDescription)")
}

7. ละเว้นการทำให้โค้ดสับสนและวิศวกรรมย้อนกลับ

ไบนารี Swift สามารถวิศวกรรมย้อนกลับได้เพื่อเปิดเผยตรรกะทางธุรกิจ อัลกอริธึม หรือความลับที่ซ่อนอยู่ ผู้โจมตีใช้เครื่องมือเช่น Hopper Disassembler, class-dump หรือ IDA Pro เพื่อถอดรหัสแอปของคุณและวิเคราะห์วิธีการทำงานภายใน ความเสี่ยงนี้มักจะถูกประเมินต่ำเกินไป โดยเฉพาะแอปขนาดเล็ก แต่แอปใดก็ตามก็สามารถตกเป็นเป้าหมายได้

ซึ่งหมายความว่าเมื่อคุณคอมไพล์แอป Swift ไบนารีผลลัพธ์ที่ได้จะประกอบด้วย:

  • ชื่อคลาสและลายเซ็นวิธีการ

  • ตัวอักษรสตริง (URL, ข้อความแสดงข้อผิดพลาด, คีย์)

  • โครงสร้างของตรรกะโค้ดของคุณ

  • การใช้งานอัลกอริทึม

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

เหตุใดจึงไม่ดี – ตัวอย่างจริง:

สมมติว่าคุณมีการตรวจสอบคุณสมบัติระดับพรีเมียมในแอปของคุณ:

class FeatureManager {
 func isPremiumUser() -> Bool {
 // Check if user has premium access
 let hasSubscription = UserDefaults.standard.bool(forKey: "premium_unlocked")
 return hasSubscription
 }
 func unlockPremiumFeature() {
 guard isPremiumUser() else {
 showPaywall()
 return
 }
 // Show premium content
 showPremiumContent()
 }
}

ผู้โจมตีสามารถย้อนกลับวิศวกรรมแอปของคุณและค้นพบวิธีการ 87 ควบคุมการเข้าถึง และเพียงตรวจสอบ 91 คีย์ชื่อ 102 . จากนั้นพวกเขาจะรู้ว่าพวกเขาสามารถใช้เครื่องมือจัดการรันไทม์เพื่อตั้งค่านี้เป็นจริง โดยข้ามเพย์วอลล์ของคุณไปโดยสิ้นเชิง

วิธีแก้ไข:

1. ใช้การเพิ่มประสิทธิภาพ Swift Compiler

เปิดใช้งานแฟล็กการเพิ่มประสิทธิภาพที่จะตัดสัญลักษณ์การดีบักและทำให้ไบนารีอ่านยากขึ้น:

// In your build settings:
// - Set "Optimization Level" to "-O" (or -Osize) for release builds
// - Enable "Strip Debug Symbols During Copy" = YES
// - Set "Strip Style" to "All Symbols"

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

<แข็งแกร่ง>2. ใช้เครื่องมือสร้างความสับสนให้กับสัญลักษณ์

เครื่องมืออย่าง SwiftShield สามารถเปลี่ยนชื่อคลาส วิธีการ และคุณสมบัติของคุณให้เป็นชื่อที่ไม่มีความหมายได้:

// Before obfuscation (readable to attackers):
class FeatureManager {
 func isPremiumUser() -> Bool { ... }
}
// After obfuscation (harder to understand):
class a7f3b2 {
 func x9k2m() -> Bool { ... }
}

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

<แข็งแกร่ง>3. ย้ายตรรกะที่ละเอียดอ่อนไปยังเซิร์ฟเวอร์ (แนวทางปฏิบัติที่ดีที่สุด)

แทนที่จะตรวจสอบสถานะพรีเมียมในเครื่อง ให้ยืนยันฝั่งเซิร์ฟเวอร์:

// ✅ Secure approach - Server validates everything
class FeatureManager {
 func unlockPremiumFeature() async {
 do {
 // Server checks if user truly has premium access
 let hasAccess = try await backend.verifyPremiumAccess(userId: currentUserId)
 if hasAccess {
 showPremiumContent()
 } else {
 showPaywall()
 }
 } catch {
 // Handle error
 showPaywall()
 }
 }
}

วิธีการทำงาน:

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

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

8. ไลบรารีของบุคคลที่สามที่ไม่ปลอดภัย

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

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

วิธีการแก้ไข:

  • ใช้เฉพาะไลบรารีคุณภาพสูงและได้รับการดูแลอย่างดีเท่านั้น

  • อัปเดตการขึ้นต่อกันและติดตาม CVE (ช่องโหว่และความเสี่ยงทั่วไป)

  • ตรวจสอบรหัสไลบรารีหากจัดการข้อมูลที่ละเอียดอ่อน

9. การตรวจสอบสิทธิ์ไบโอเมตริกซ์และหลายปัจจัยไม่เพียงพอ

แอปพลิเคชันส่วนใหญ่อาศัยรหัสผ่านเพียงอย่างเดียว ซึ่งเสี่ยงต่อการถูกแฮ็ก การเปิดใช้งานข้อมูลไบโอเมตริก เช่น Face ID หรือ Touch ID จะช่วยเพิ่มความปลอดภัยให้กับผู้ใช้

วิธีการแก้ไข:

  • ผูกกรอบ LocalAuthentication สำหรับการตรวจสอบสิทธิ์แบบไบโอเมตริกซ์

  • รวมข้อมูลไบโอเมตริกเข้ากับการตรวจสอบสิทธิ์บนเซิร์ฟเวอร์สำหรับการตรวจสอบสิทธิ์แบบหลายปัจจัย (MFA)

import LocalAuthentication
let context = LAContext()
var error: NSError?
if context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
 context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics,
 localizedReason: "Access your account") { success, authError in
 DispatchQueue.main.async {
 if success {
 // Proceed securely
 } else {
 // Handle failure (authError may contain the reason)
 print("Authentication failed: \(authError?.localizedDescription ?? "Unknown error")")
 }
 }
}
} else {
// Biometrics not available, check error for details
 print("Biometrics unavailable: \(error?.localizedDescription ?? "Unknown error")")
}

10. ไม่สนใจการทดสอบความปลอดภัยเป็นระยะ

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

การทดสอบความปลอดภัยควรเกิดขึ้นในหลายขั้นตอน โดยใช้เครื่องมือและแนวทางปฏิบัติที่สามารถเข้าถึงได้:

  1. การสแกนความปลอดภัยอัตโนมัติ: ทำงานโดยอัตโนมัติกับทุกบิวด์เพื่อตรวจจับปัญหาทั่วไป

  2. การตรวจสอบโค้ดที่ดำเนินการด้วยตนเอง: การตรวจสอบโค้ดของคุณโดยเน้นเรื่องความปลอดภัยเป็นประจำโดยใช้แนวทางที่กำหนดไว้

  3. เครื่องมือสแกนช่องโหว่: ใช้เครื่องมือฟรีเช่น MobSF เพื่อวิเคราะห์แอปของคุณเพื่อหาข้อบกพร่องด้านความปลอดภัย

  4. การตรวจสอบการพึ่งพา: การตรวจสอบไลบรารีของบุคคลที่สามเพื่อหาช่องโหว่ด้านความปลอดภัยที่ทราบ

วิธีแก้ไข:

1. ใช้การสแกนความปลอดภัยอัตโนมัติใน CI/CD

รวมเครื่องมือสแกนความปลอดภัยเข้ากับไปป์ไลน์การผสานรวมอย่างต่อเนื่องของคุณ เพื่อให้ตรวจสอบการเปลี่ยนแปลงโค้ดทุกครั้งโดยอัตโนมัติ:

# Example: GitHub Actions workflow for automated security scanning
name: Security Scan
on: [push, pull_request]
jobs:
 security-scan:
 runs-on: macos-latest
 steps:
 - name: Checkout code
 uses: actions/checkout@v3
 - name: Run MobSF Security Scan
 run: |
 # Mobile Security Framework - scans for common vulnerabilities
 docker run -v $(pwd):/app opensecurity/mobile-security-framework-mobsf
 - name: Dependency Vulnerability Check
 run: |
 # Check CocoaPods/SPM dependencies for known CVEs
 brew install dependency-check
 dependency-check --scan ./Podfile.lock --format JSON
 - name: Secret Detection
 run: |
 # Detect accidentally committed secrets
 brew install truffleHog
 truffleHog filesystem . --json
 - name: Fail build on critical issues
 run: |
 if grep -q "CRITICAL" security-report.json; then
 echo "Critical security issues found!"
 exit 1
 fi

ตรวจสอบการสแกนอัตโนมัติสำหรับ:

  • คีย์ API โทเค็นหรือรหัสผ่านแบบฮาร์ดโค้ด

  • การกำหนดค่าเครือข่ายไม่ปลอดภัย (อนุญาต HTTP แทน HTTPS)

  • อัลกอริธึมการเข้ารหัสที่อ่อนแอ

  • ช่องโหว่ที่ทราบในไลบรารีบุคคลที่สาม

  • การตรวจสอบใบรับรอง SSL/TLS ที่ไม่เหมาะสม

  • การจัดเก็บข้อมูลที่ไม่ปลอดภัย (การจัดเก็บข้อมูลที่ละเอียดอ่อนใน UserDefaults)

  • สิทธิ์ของแอปมากเกินไป

ตัวอย่างผลลัพธ์จากการสแกนอัตโนมัติ:

Security Scan Results:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[CRITICAL] Hardcoded API Key Found
 File: APIClient.swift:15
 Issue: API key "sk_live_abc123..." detected in source code
[HIGH] Insecure HTTP Connection
 File: NetworkManager.swift:42
 Issue: App allows cleartext HTTP traffic to api.example.com
 Fix: Enforce HTTPS or add exception to Info.plist if required
[MEDIUM] Weak Encryption Algorithm
 File: DataEncryption.swift:28
 Issue: Using MD5 for hashing (cryptographically broken)
 Fix: Use SHA-256 or better
[LOW] Outdated Dependency
 Library: Alamofire 4.2.0
 Issue: Known vulnerability CVE-2021-12345
 Fix: Update to version 5.6.0 or later
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Build Failed: 2 critical issues must be fixed before deployment

<แข็งแกร่ง>2. ใช้ MobSF (กรอบงานความปลอดภัยบนมือถือ) สำหรับการวิเคราะห์ช่องโหว่

MobSF เป็นเครื่องมืออัตโนมัติฟรีที่วิเคราะห์แอป iOS ของคุณเพื่อหาปัญหาด้านความปลอดภัย:

# Install and run MobSF locally
docker pull opensecurity/mobile-security-framework-mobsf
docker run -it -p 8000:8000 opensecurity/mobile-security-framework-mobsf
# Upload your .ipa file through the web interface at localhost:8000
# MobSF will analyze and provide a detailed security report

สิ่งที่ MobSF ตรวจสอบ:

  • การวิเคราะห์แบบไบนารีสำหรับความลับแบบฮาร์ดโค้ด

  • รูปแบบการจัดเก็บข้อมูลที่ไม่ปลอดภัย

  • การใช้งานการเข้ารหัสที่อ่อนแอ

  • การเชื่อมต่อเครือข่ายที่ไม่ปลอดภัย

  • แนวทางปฏิบัติที่ดีที่สุดด้านคุณภาพและความปลอดภัยของโค้ด

  • การปฏิบัติตามมาตรฐานความปลอดภัย

<แข็งแกร่ง>3. ดำเนินการตรวจสอบโค้ดเป็นประจำโดยใช้ OWASP MSTG

ใช้คู่มือการทดสอบความปลอดภัยบนมือถือ OWASP เป็นรายการตรวจสอบเพื่อตรวจสอบโค้ดของคุณเอง:

// Example: Following OWASP MSTG recommendations for secure storage
class SecureStorage {
 // ❌ Insecure - UserDefaults is not encrypted
 func saveTokenInsecurely(_ token: String) {
 UserDefaults.standard.set(token, forKey: "authToken")
 }
 // ✅ Secure - Using Keychain as OWASP recommends
 func saveTokenSecurely(_ token: String) throws {
 let data = token.data(using: .utf8)!
 let query: [String: Any] = [
 kSecClass as String: kSecClassGenericPassword,
 kSecAttrAccount as String: "authToken",
 kSecValueData as String: data,
 kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
 ]
 SecItemDelete(query as CFDictionary)
 let status = SecItemAdd(query as CFDictionary, nil)
 guard status == errSecSuccess else {
 throw StorageError.saveFailed
 }
 }
}

รายการตรวจสอบ OWASP MSTG สำหรับการตรวจสอบตนเอง:

  • [ ] ข้อมูลที่ละเอียดอ่อนทั้งหมดได้รับการเข้ารหัสเมื่อไม่มีการใช้งานหรือไม่

  • [ ] HTTPS บังคับใช้กับการโทรทุกเครือข่ายหรือไม่

  • [ ] มีการตรวจสอบใบรับรองอย่างถูกต้องหรือไม่

  • [ ] ข้อมูลที่ละเอียดอ่อนถูกแยกออกจากบันทึกหรือไม่

  • [ ] คีย์ API และความลับไม่ได้ฮาร์ดโค้ดใช่หรือไม่

  • [ ] อินพุตของผู้ใช้ได้รับการตรวจสอบและฆ่าเชื้อแล้วหรือไม่

  • [ ] โทเค็นการรับรองความถูกต้องถูกเก็บไว้อย่างปลอดภัยในพวงกุญแจหรือไม่

<แข็งแกร่ง>4. การสแกนการพึ่งพาอัตโนมัติ

ตรวจสอบการพึ่งพาของคุณอย่างต่อเนื่องเพื่อหาช่องโหว่ที่เพิ่งค้นพบ:

# For CocoaPods projects
gem install cocoapods-audit
pod audit
# For Swift Package Manager
# Use GitHub Dependabot (free for public repos) or
brew install swift-outdated
swift-outdated

และตั้งค่าการแจ้งเตือนอัตโนมัติด้วยเครื่องมือเหล่านี้:

  • ขึ้นอยู่กับ GitHub: สร้าง PR โดยอัตโนมัติเมื่อตรวจพบการพึ่งพาที่มีช่องโหว่ (ฟรี)

  • สนิก :ระดับฟรีสำหรับโครงการโอเพ่นซอร์ส

  • การตรวจสอบการพึ่งพา OWASP: เครื่องมือบรรทัดคำสั่งฟรี

บทสรุป

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

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

การทดสอบช่องโหว่ด้านความปลอดภัยเป็นประจำและการจำกัดการใช้ไลบรารีของบุคคลที่สามยังช่วยเพิ่มความปลอดภัยให้กับแอปของคุณได้อีกด้วย

การรักษาความปลอดภัยเป็นความรับผิดชอบอย่างต่อเนื่อง Swift มีเครื่องมือให้ แต่นักพัฒนาจำเป็นต้องใช้เครื่องมือเหล่านั้นอย่างระมัดระวัง การรักษาความปลอดภัยที่ได้รับการจัดการตั้งแต่เริ่มต้นจะปกป้องข้อมูลของผู้ใช้ สร้างความไว้วางใจ และปกป้องชื่อเสียงของแอปพลิเคชัน

เรียนรู้การเขียนโค้ดฟรี หลักสูตรโอเพ่นซอร์สของ freeCodeCamp ช่วยให้ผู้คนมากกว่า 40,000 คนได้งานในตำแหน่งนักพัฒนา เริ่มต้น