บทความนี้อธิบายวิธีการใช้การตรวจสอบสิทธิ์สองทาง SSL ใน Java แบ่งปันสำหรับการอ้างอิงของคุณดังนี้:
การตรวจสอบ SSL ทั่วไปเป็นเรื่องธรรมดามากขึ้น ตรวจสอบว่าเซิร์ฟเวอร์ของเราเป็นจริงหรือถูกต้อง แน่นอนถ้า URL ที่คุณกำลังเยี่ยมชมนั้นผิดเลยไม่มีใครสามารถทำได้ สิ่งนี้เรียกว่าการตรวจสอบสิทธิ์ทางเดียว SSL
แต่ในความเป็นจริงเราอาจตรวจสอบว่าลูกค้าตรงตามข้อกำหนดนั่นคือออกใบรับรองให้กับผู้ใช้แต่ละคนของเราหรือไม่และใบรับรองดิจิตอลแต่ละใบนั้นไม่ซ้ำกันและไม่ใช่สาธารณะ ด้วยวิธีนี้คุณสามารถมั่นใจได้ว่าผู้ใช้ที่เข้าถึงเซิร์ฟเวอร์ของฉันได้รับการยอมรับจากเซิร์ฟเวอร์และไม่สามารถเข้าถึงได้โดยผู้อื่น
การรับรองความถูกต้องแบบสองทางทำให้มั่นใจได้ว่าทั้งเซิร์ฟเวอร์และไคลเอนต์จะรับรู้ซึ่งกันและกันในระดับแรก จากนั้นหากพวกเขาต้องการสื่อสารพวกเขาจะแนบโปรโตคอล SSL เข้ากับโปรโตคอลการสื่อสารเพื่อให้แน่ใจว่าเนื้อหาของการสื่อสารถูกเข้ารหัส แม้แต่เครื่องมือดมกลิ่นเครือข่ายเช่นดมกลิ่นก็ยังดูรหัสที่อ่านไม่ออก ในอนาคตฉันจะแสดงให้คุณเห็นสิ่งที่คุณเห็นด้วยดมกลิ่นโดยไม่ต้องเข้ารหัส ฉันกลัวว่าคุณจะระมัดระวังมากขึ้นด้วยวิธีนี้
เนื้อหาต่อไปนี้ถูกตัดตอนมาจากอินเทอร์เน็ตและแก้ไขหลังจากการตรวจสอบจริง
สถานการณ์จำลอง:
เมื่อฝั่งเซิร์ฟเวอร์สื่อสารกับฝั่งไคลเอ็นต์การอนุญาตและการตรวจสอบตัวตนเป็นสิ่งจำเป็นนั่นคือไคลเอนต์สามารถรับข้อความจากเซิร์ฟเวอร์ได้เท่านั้นและเซิร์ฟเวอร์สามารถรับข้อความจากไคลเอนต์ได้เท่านั้น
เทคโนโลยีการดำเนินการ:
JSSE (ส่วนขยายซ็อกเก็ตความปลอดภัยของ Java)
เป็นโซลูชันที่เปิดตัวโดย Sun เพื่อแก้ปัญหาการสื่อสารที่ปลอดภัยบนอินเทอร์เน็ต มันใช้โปรโตคอล SSL และ TSL (การรักษาความปลอดภัยเลเยอร์การขนส่ง) JSSE รวมถึงเทคโนโลยีเช่นการเข้ารหัสข้อมูลการตรวจสอบเซิร์ฟเวอร์ความสมบูรณ์ของข้อความและการตรวจสอบไคลเอนต์ ด้วยการใช้ JSSE นักพัฒนาสามารถถ่ายโอนข้อมูลระหว่างไคลเอนต์และเซิร์ฟเวอร์ได้อย่างปลอดภัยผ่านโปรโตคอล TCP/IP
เพื่อใช้การตรวจสอบข้อความ
เซิร์ฟเวอร์ต้องการ:
1) Keystore: ที่บันทึกคีย์ส่วนตัวของเซิร์ฟเวอร์
2) Trust Keystore: ช่วยประหยัดใบรับรองการอนุญาตของลูกค้า
ในทำนองเดียวกันลูกค้าต้องการ:
1) Keystore: ที่บันทึกคีย์ส่วนตัวของลูกค้า
2) Trust Keystore: ที่นี่ฉันขอแนะนำให้ใช้คำสั่ง keytool ที่มาพร้อมกับ Java เพื่อสร้างไฟล์ข้อมูลดังกล่าว แน่นอน OpenSSL ยังเป็นรุ่นใบรับรอง SSL โอเพนซอร์สที่ได้รับความนิยมมากที่สุด OpenSSL เขียนเป็นภาษา C, Cross-System อย่างไรก็ตามเราอาจพิจารณาความสะดวกในการใช้โปรแกรม Java เพื่อสร้างใบรับรองในอนาคตและใช้ keytool ที่มาพร้อมกับ JDK
1) สร้างคีย์ส่วนตัวเซิร์ฟเวอร์และนำเข้าสู่ไฟล์คีย์เซิร์ฟเวอร์
keytool -gey -alias serverkey -keystore kserver.keystore
ในระหว่างกระบวนการคุณต้องกรอกข้อมูลแยกต่างหากและตั้งค่าตามความต้องการของคุณ
รหัสผ่านคีย์สโตร์: 123456
นามสกุลและนามสกุล: จิน
ชื่อหน่วยขององค์กร: ไม่มี
ชื่อองค์กร: ไม่มี
ชื่อเมืองหรือภูมิภาค: BJ
ชื่อรัฐหรือจังหวัด: BJ
รหัสประเทศ: CN
รหัสผ่านของคีย์ส่วนตัว ServerKey ไม่ได้กรอกไว้เหมือนกับรหัสผ่านของ Keystore อย่าลืมให้ความสนใจที่นี่เพียงกด Enter โดยไม่ต้องเปลี่ยนรหัสผ่าน มิฉะนั้นหากไม่สามารถใช้คีย์ส่วนตัวนี้ได้โดยตรงในโปรแกรมที่ตามมาจะมีการรายงานข้อผิดพลาด
คุณสามารถสร้างไฟล์ kserver.keystore
Server.keyStore ใช้สำหรับเซิร์ฟเวอร์ซึ่งเก็บคีย์ส่วนตัวของตัวเอง
2) ส่งออกใบรับรองเซิร์ฟเวอร์ตามคีย์ส่วนตัว
keytool -Export -AliAs ServerKey -KeyStore KServer.keystore -file Server.crt
Server.crt เป็นใบรับรองทางฝั่งเซิร์ฟเวอร์
3) นำเข้าใบรับรองเซิร์ฟเวอร์ลงในคีย์ Trust ของลูกค้า
keytool -import -alias serverkey -file server.crt -keystore tclient.keystore
TClient.KeyStore มีไว้สำหรับลูกค้าและมีใบรับรองที่เชื่อถือได้
ในทำนองเดียวกันสร้างคีย์ส่วนตัวของลูกค้าและใบรับรองของลูกค้าและนำเข้าสู่คีย์ Trust ของเซิร์ฟเวอร์
1) keytool -genkey -alias clientkey -keystore kclient.keystore
2) keytool -Export -AliAs ClientKey -KeyStore KClient.KeyStore -File Client.crt
3) keytool -import -alias clientkey -file client.crt -keystore tserver.keystore
ด้วยวิธีนี้ไฟล์ที่สร้างจะแบ่งออกเป็นสองกลุ่ม
เซิร์ฟเวอร์บันทึก: kserver.keystore tserver.keystore
ลูกค้าบันทึก: kclient.keystore tclient.kystore
ต่อไปนี้คือการตรวจสอบว่าใบรับรองที่เราสร้างนั้นมีให้ผ่านโปรแกรมการสื่อสาร Java Socket
ลูกค้า:
ตัวอย่างแพ็คเกจ. ssl; นำเข้า java.io.bufferedInputstream; นำเข้า java.io.bufferedOutputstream; นำเข้า java.io.fileinputstream; นำเข้า java.io.ioException; นำเข้า java.io.inputstream; javax.net.ssl.keyManagerFactory; นำเข้า javax.net.ssl.sslcontext; นำเข้า Javax.net.ssl.sslsocket; นำเข้า Javax.net.ssl.trustManagerFactory; INT สุดท้ายคงที่ int default_port = 7777; สตริงสุดท้ายคงที่ส่วนตัว client_key_store_password = "123456"; สตริงสุดท้ายคงที่ส่วนตัว client_trust_key_store_password = "123456"; SSLSocket ส่วนตัว SSLSocket; / ** * เริ่มโปรแกรมไคลเอนต์ * * @param args */ โมฆะคงที่สาธารณะหลัก (สตริง [] args) {sslClient client = new SSLClient (); client.init (); client.process (); } / *** เชื่อมต่อกับเซิร์ฟเวอร์ผ่านซ็อกเก็ต SSL และส่งข้อความ* / กระบวนการโมฆะสาธารณะ () {ถ้า (sslsocket == null) {system.out.println ("ข้อผิดพลาด"); กลับ; } ลอง {inputStream input = sslSocket.getInputStream (); outputstream output = sslsocket.getOutputStream (); bufferedInputStream bis = ใหม่ bufferedInputStream (อินพุต); BufferedOutputStream BOS = ใหม่ bufferedOutputStream (เอาต์พุต); bos.write ("ข้อความลูกค้า" .getBytes ()); bos.flush (); ไบต์ [] บัฟเฟอร์ = ไบต์ใหม่ [20]; bis.read (บัฟเฟอร์); System.out.println (สตริงใหม่ (บัฟเฟอร์)); sslsocket.close (); } catch (ioexception e) {system.out.println (e); }}/** * <ul> * <li> ประเด็นสำคัญของการเชื่อมต่อ SSL: </li> * <li> เริ่มต้น SSLSocket </li> * <li> นำเข้าคีย์คีย์ส่วนตัวไคลเอน sslContext.getInstance ("SSL"); KeyManagerFactory KMF = KeyManagerFactory.getInstance ("Sunx509"); TrustManagerFactory TMF = TrustManagerFactory.getInstance ("Sunx509"); KeyStore KS = KeyStore.getInstance ("JKS"); Keystore tks = keystore.getInstance ("JKS"); ks.load (ใหม่ fileInputStream ("e: //klient.keystore"), client_key_store_password.tochararray ()); tks.load (ใหม่ FileInputStream ("e: //tclient.keystore"), client_trust_key_store_password.tochararray ()); kmf.init (ks, client_key_store_password.tochararray ()); tmf.init (tks); ctx.init (kmf.getKeyManagers (), tmf.getTrustManagers (), null); sslsocket = (sslsocket) ctx.getsocketfactory (). createsocket (default_host, default_port); } catch (exception e) {system.out.println (e); -ด้านเซิร์ฟเวอร์:
ตัวอย่างแพ็คเกจ. ssl; นำเข้า java.io.bufferedInputstream; นำเข้า java.io.bufferedOutputstream; นำเข้า java.io.fileinputstream; นำเข้า java.io.inputstream; นำเข้า Java.io.OutputStream; นำเข้า Java.net.socket; javax.net.ssl.keyManagerFactory; นำเข้า javax.net.ssl.sslcontext; นำเข้า Javax.net.ssl.sslserversocket; javax.net.ssl.TrustManagerFactory;/*********************************************************************************************************************************************** - - - - - - - ServerKey -keystore kserver.keystore -file server.crt </li> * <li> 3) เพิ่มใบรับรองลงในคีย์สโตร์ที่เชื่อถือได้ของไคลเอนต์ </li> * <li> keytool -import -alias server -file server.crt -keystore tclient.keystore </li> - - - - - - - - เซิร์ฟเวอร์ * */คลาสสาธารณะ sslserver {ส่วนตัวคงที่ int final int default_port = 7777; สตริงสุดท้ายคงที่ส่วนตัวเซิร์ฟเวอร์ _key_store_password = "123456"; สตริงสุดท้ายคงที่ส่วนตัวเซิร์ฟเวอร์ _trust_key_store_password = "123456"; SSLServersocket ส่วนตัว Serversocket; / ** * เริ่มโปรแกรม * * @param args */ โมฆะคงที่สาธารณะหลัก (สตริง [] args) {sslserver server = sslserver ใหม่ (); Server.init (); Server.start (); }/** * <ul> * <li> ฟังซ็อกเก็ตเซิร์ฟเวอร์ SSL </li> * <li> เนื่องจากโปรแกรมนี้ไม่ใช่การสาธิตการฟังซ็อกเก็ตมันเพียงแค่ใช้รูปแบบเธรดเดี่ยวและยอมรับข้อความของลูกค้า กลับ; } ในขณะที่ (จริง) {ลอง {ซ็อกเก็ต s = serversocket.accept (); inputstream อินพุต = s.getInputStream (); เอาท์พุทเอาท์พุท = s.getOutputStream (); bufferedInputStream bis = ใหม่ bufferedInputStream (อินพุต); BufferedOutputStream BOS = ใหม่ bufferedOutputStream (เอาต์พุต); ไบต์ [] บัฟเฟอร์ = ไบต์ใหม่ [20]; bis.read (บัฟเฟอร์); System.out.println (สตริงใหม่ (บัฟเฟอร์)); bos.write ("เซิร์ฟเวอร์ echo" .getBytes ()); bos.flush (); s.close (); } catch (exception e) {system.out.println (e); }}}}/** * <ul> * <li> ประเด็นสำคัญของการเชื่อมต่อ SSL: </li> * <li> เริ่มต้น SSLServersocket </li> * <li> นำเข้าคีย์คีย์ส่วนตัวเซิร์ฟเวอร์และนำเข้าคีย์สโตร์ที่เชื่อถือได้ sslContext.getInstance ("SSL"); KeyManagerFactory KMF = KeyManagerFactory.getInstance ("Sunx509"); TrustManagerFactory TMF = TrustManagerFactory.getInstance ("Sunx509"); KeyStore KS = KeyStore.getInstance ("JKS"); Keystore tks = keystore.getInstance ("JKS"); Ks.Load (ใหม่ FileInputStream ("e: //kserver.keystore"), server_key_store_password.tochararray ()); tks.load (ใหม่ FileInputStream ("e: //tserver.keystore"), server_trust_key_store_password.tochararray ()); kmf.init (ks, server_key_store_password.tochararray ()); tmf.init (tks); ctx.init (kmf.getKeyManagers (), tmf.getTrustManagers (), null); serversocket = (sslserversocket) ctx.getServersocketFactory (). createServersocket (default_port); Serversocket.setneedClientauth (จริง); } catch (exception e) {e.printstacktrace (); -สำหรับข้อมูลเพิ่มเติมเกี่ยวกับเนื้อหาที่เกี่ยวข้องกับ Java โปรดตรวจสอบหัวข้อของไซต์นี้: "โครงสร้างข้อมูล Java และการสอนอัลกอริทึม", "บทสรุปของการดำเนินการ Java DOM TIPS TIPS", "บทสรุปของไฟล์ Java และเคล็ดลับการดำเนินการไดเรกทอรี"
ฉันหวังว่าบทความนี้จะเป็นประโยชน์กับการเขียนโปรแกรม Java ของทุกคน