คำนำ
เมื่อเร็ว ๆ นี้ปัญหาที่เกี่ยวข้องกับ HTTPS จำเป็นต้องได้รับการแก้ไขดังนั้นฉันจึงใช้เวลาเรียนรู้การใช้แพลตฟอร์ม Android HTTPS และในเวลาเดียวกันฉันก็อ่านหลักการบางอย่างของ HTTPS
หลักการ https
HTTPS (Hyper Text Transfer Protocol Secure) เป็น HTTP ตาม SSL/TLS โปรโตคอล HTTPS ขึ้นอยู่กับโปรโตคอล HTTP เพิ่มการจับมือ SSL/TLS และการส่งข้อมูลการเข้ารหัสข้อมูลซึ่งเป็นของโปรโตคอลเลเยอร์แอปพลิเคชัน ดังนั้นหลักการของการศึกษาโปรโตคอล HTTPS ในที่สุดก็เพื่อศึกษาโปรโตคอล SSL/TLS
เอฟเฟกต์โปรโตคอล SSL/TLS
การสื่อสาร HTTP ที่ไม่มี SSL/TLS ไม่ใช่การสื่อสารที่เข้ารหัส
1. การดักฟังความเสี่ยง: บุคคลที่สามสามารถเรียนรู้เกี่ยวกับเนื้อหาการสื่อสาร
2. ความเสี่ยงของการดัดแปลง: บุคคลที่สามสามารถแก้ไขเนื้อหาของการแจ้งเตือนได้
3. ความเสี่ยงของสารตั้งต้น: บุคคลที่สามสามารถแกล้งทำเป็นตัวตนของผู้อื่นเพื่อเข้าร่วมการสื่อสาร
โปรโตคอล SSL/TLS ได้รับการออกแบบมาเพื่อแก้ปัญหาความเสี่ยงทั้งสามนี้
1. ข้อมูลทั้งหมดถูกเข้ารหัสและบุคคลที่สามไม่สามารถดักฟังได้
2. มีกลไกการตรวจสอบ
3. ติดตั้งใบรับรอง ID เพื่อป้องกันไม่ให้มีตัวตนจากการปลอมตัว
กระบวนการดำเนินการพื้นฐาน
แนวคิดพื้นฐานของโปรโตคอล SSL/TLS คือการใช้วิธีการเข้ารหัสคีย์สาธารณะนั่นคือไคลเอนต์ขอคีย์สาธารณะไปยังเซิร์ฟเวอร์ก่อนจากนั้นใช้คีย์สาธารณะเพื่อเข้ารหัสข้อมูล มันจะถูกถอดรหัสด้วยคีย์ส่วนตัวของตัวเอง แต่ที่นี่คุณต้องเข้าใจวิธีแก้ปัญหาทั้งสอง
1. จะตรวจสอบให้แน่ใจได้อย่างไรว่าคีย์สาธารณะไม่ได้ถูกดัดแปลงด้วย?
วิธีแก้ปัญหา: วางคีย์สาธารณะในใบรับรองดิจิตอล ตราบใดที่ใบรับรองมีความน่าเชื่อถือคีย์สาธารณะก็น่าเชื่อถือ
2. ปริมาณการเข้ารหัสคีย์สาธารณะมีขนาดใหญ่เกินไปวิธีลดการใช้เวลา?
วิธีแก้ปัญหา: แต่ละบทสนทนาไคลเอนต์และเซิร์ฟเวอร์สร้าง "คีย์เซสชัน" (คีย์เซสชัน) เพื่อเข้ารหัสข้อมูล เนื่องจาก "คีย์บทสนทนา" คือการเข้ารหัสแบบสมมาตรความเร็วในการดำเนินการจึงเร็วมากและคีย์สาธารณะเซิร์ฟเวอร์จึงใช้เพื่อเข้ารหัส "คีย์บทสนทนา" ซึ่งจะช่วยลดการใช้เวลาของการดำเนินการที่เข้ารหัส
ดังนั้นกระบวนการพื้นฐานของโปรโตคอล SSL/TLS จึงเป็นเช่นนี้:
1. ไคลเอนต์ถูกร้องขอไปยังเซิร์ฟเวอร์และตรวจสอบคีย์สาธารณะ
2. ทั้งสองฝ่ายเจรจาและสร้าง "คีย์บทสนทนา"
3. ทั้งสองฝ่ายใช้ "คีย์บทสนทนา" เพื่อทำการสื่อสารที่เข้ารหัส
ผ้าสองผ้าแรกในกระบวนการข้างต้นเรียกอีกอย่างว่า "Handshake Stage"
กระบวนการโดยละเอียดของขั้นตอนการจับมือกัน
"Handhake Stage" เกี่ยวข้องกับการสื่อสารสี่ครั้ง
ลูกค้าออกคำขอ (clienthello)
ก่อนอื่นไคลเอนต์ (โดยปกติจะเป็นเบราว์เซอร์) ส่งคำขอสำหรับการสื่อสารที่เข้ารหัสไปยังเซิร์ฟเวอร์ซึ่งเรียกว่าคำขอไคลเอนต์เฮลโล ในขั้นตอนนี้ไคลเอนต์ส่วนใหญ่จะให้ข้อมูลต่อไปนี้กับเซิร์ฟเวอร์:
1. เวอร์ชันโปรโตคอลที่รองรับเช่นเวอร์ชัน TLS 1.0
2. หมายเลขสุ่มที่สร้างโดยไคลเอนต์จะถูกใช้ในภายหลังเพื่อสร้าง "คีย์บทสนทนา"
3. วิธีการเข้ารหัสที่รองรับได้เช่นการเข้ารหัสคีย์สาธารณะ RSA
4. วิธีการสนับสนุนการบีบอัด
ควรสังเกตว่าข้อมูลที่ส่งโดยลูกค้าไม่รวมชื่อโดเมนของเซิร์ฟเวอร์ กล่าวอีกนัยหนึ่งเซิร์ฟเวอร์เชิงทฤษฎีสามารถมีเพียงเว็บไซต์เดียวมิฉะนั้นจะไม่ชัดเจนว่าใบรับรองดิจิตอลใดที่เว็บไซต์ให้บริการลูกค้า นี่คือเหตุผลที่เซิร์ฟเวอร์มักจะมีใบรับรองดิจิตอลเพียงหนึ่งใบ
ServerHello
หลังจากเซิร์ฟเวอร์ได้รับคำขอไคลเอนต์จะตอบกลับไคลเอนต์เรียกว่า ServerHello การตอบสนองของเซิร์ฟเวอร์รวมถึงเนื้อหาต่อไปนี้:
1. ยืนยันรุ่นโปรโตคอลการสื่อสารที่เข้ารหัสเช่นเวอร์ชัน TLS 1.0 หากเบราว์เซอร์ไม่สอดคล้องกับเวอร์ชันที่รองรับโดยเซิร์ฟเวอร์เซิร์ฟเวอร์จะปิดการสื่อสารที่เข้ารหัส
2. หมายเลขสุ่มที่สร้างโดยเซิร์ฟเวอร์จะใช้ในภายหลังเพื่อสร้าง "คีย์บทสนทนา"
3. ยืนยันวิธีการเข้ารหัสที่ใช้เช่นการเข้ารหัสคีย์สาธารณะ RSA
4. ใบรับรองเซิร์ฟเวอร์
นอกเหนือจากข้อมูลข้างต้นหากเซิร์ฟเวอร์จำเป็นต้องยืนยันตัวตนของไคลเอนต์จะมีการร้องขออื่นขอให้ไคลเอ็นต์ให้ "ใบรับรองไคลเอนต์" ตัวอย่างเช่นสถาบันการเงินมักอนุญาตให้ลูกค้าที่ผ่านการรับรองสามารถเชื่อมต่อกับเครือข่ายของตนเองและจะให้คีย์ USB แก่ลูกค้าที่เป็นทางการซึ่งมีใบรับรองลูกค้า
หลังจากไคลเอนต์ตอบกลับไคลเอนต์ได้รับการตอบกลับเซิร์ฟเวอร์ใบรับรองเซิร์ฟเวอร์จะตรวจสอบเซิร์ฟเวอร์ก่อน หากใบรับรองไม่ได้ออกโดยสถาบันที่เชื่อถือ .
หากไม่มีปัญหากับใบรับรองลูกค้าจะนำคีย์สาธารณะออกจากใบรับรอง จากนั้นส่งข้อความสามข้อความต่อไปนี้ไปยังเซิร์ฟเวอร์
1. หมายเลขสุ่ม จำนวนสุ่มของเซิร์ฟเวอร์ถูกเข้ารหัสเพื่อป้องกันการแตะ
2. การแจ้งเตือนการเปลี่ยนแปลงรหัสซึ่งระบุว่าข้อมูลที่ตามมาจะถูกส่งด้วยวิธีการเข้ารหัสและคีย์ที่ตกลงกันโดยทั้งสองฝ่าย
3. การจับมือลูกค้าสิ้นสุดการแจ้งเตือนซึ่งระบุว่าขั้นตอนการจับมือกันของลูกค้าสิ้นสุดลง รายการนี้มักจะเป็นค่าแฮชของเนื้อหาทั้งหมดของการตรวจสอบก่อนหน้านี้ไปยังเซิร์ฟเวอร์
หมายเลขสุ่มแรกด้านบนเป็นหมายเลขสุ่มที่สามที่ปรากฏในขั้นตอนการจับมือกันทั้งหมดหรือที่เรียกว่า "คีย์พรีมาสเตอร์" ด้วยมันไคลเอนต์และเซิร์ฟเวอร์มีตัวเลขสุ่มสามตัวในเวลาเดียวกันจากนั้นทั้งสองฝ่ายใช้วิธีการเข้ารหัสที่ตกลงกันล่วงหน้าเพื่อสร้าง "คีย์เซสชัน" เดียวกันที่ใช้ในเซสชัน
หลังจากเซิร์ฟเวอร์ตอบกลับสุดท้ายของเซิร์ฟเวอร์ได้รับคีย์ Pre-Master หมายเลขสุ่มที่สามจากไคลเอนต์ให้คำนวณ "คีย์เซสชัน" ที่ใช้ในเซสชันที่สร้างขึ้น จากนั้นส่งข้อมูลต่อไปนี้ไปยังลูกค้า
1. การแจ้งเตือนการเปลี่ยนแปลงรหัสระบุว่าข้อมูลที่ตามมาจะถูกส่งด้วยวิธีการเข้ารหัสและคีย์ที่ตกลงกันโดยทั้งสองฝ่าย
2. การจับมือเซิร์ฟเวอร์สิ้นสุดการแจ้งเตือนซึ่งระบุว่าขั้นตอนการจับมือของเซิร์ฟเวอร์สิ้นสุดลงแล้ว รายการนี้ยังเป็นค่าแฮชของเนื้อหาก่อนหน้าทั้งหมดซึ่งใช้สำหรับการตรวจสอบไคลเอนต์
ปลายจับมือ
ณ จุดนี้เวทีการจับมือทั้งหมดสิ้นสุดลง ถัดไปไคลเอนต์และเซิร์ฟเวอร์ป้อนการสื่อสารที่เข้ารหัสซึ่งใช้โปรโตคอล HTTP ธรรมดา แต่ใช้เนื้อหาการเข้ารหัส "คีย์เซสชัน"
เซิร์ฟเวอร์สร้างไซต์เสมือน HTTPS ตาม NGINX
บทความก่อนหน้านี้แนะนำในรายละเอียดเกี่ยวกับวิธีการสร้างใบรับรอง SSL บนฝั่งเซิร์ฟเวอร์และสร้างเซิร์ฟเวอร์ HTTPS ตาม NGINX, ลิงค์: NGINX สร้างเซิร์ฟเวอร์ HTTPS
การใช้งานการสื่อสาร HTTPS ของ Android
ด้วยเหตุผลหลายประการให้ใช้คลาส HTTPCLICENT เพื่ออธิบายวิธีการสร้างการเชื่อมต่อ HTTPS การสาธิตรหัสมีดังนี้
mainactivity.java
com.example.Photocrop; client.httpclient; นำเข้า Android.util.log; super.oncreate (savedinstancestate); ) {runhttpsconnecti on ();}}); httpstask.getstatus () == statushed) {httpstst ask = ใหม่ createhtpsconntask (); sbuffer = new StringBuffer (); ; if (httpresponse! = null) {statusline statusline = httpresponse.getStatusline (); (http response.getEntity (). getContent (), "UTF-8"); (ข้อยกเว้น e) {log.e ("https", e.getMessage ()); ) {log.e ("https", e.getMessage ()); .toString ());}}}}
httputils.java
com.example.photocrop; conn.scheme.scheme; .Apache.params.basichtpparams; Newttppara MS (); Schemeregistry (); ); ) {basichtpparams params = basichttpparams ใหม่ (); Schreg.register (โครงการใหม่ ( "HTTP", PlainsocketSocketSocketFactory (), 80); httpClient getSpect (บริบท) {basichtpparams params = ใหม่ basichtpparams (); (Params, true); Schemeregistry () ;; โครงการใหม่ ("http", plainsocketfactory.getsocketfactory (), 80)); }}
Activity_main.xml
<linearlayout xmlns: Android = "http://schemas.android.com/apk/res/android" xmlns: tools = "http://schemas.android.com" Android: lay_width = "Match_parent" Android "Match_Pareat" Android: Orientation = "Vertical"> <ปุ่ม Android: id = "@+id/create_button" Android: layout_ "match_ parent" id: layout_height = "wrap_content" Android: text = "@string/hello_world textsize = "16sp" /> <textView Android: id = "@+id /content_textview" Android: layout_width = "match_parent" Android: layout_height = "wra p_content" Android: gravity = "center" /> </ linearlayout>
Android ใช้ defaulthttpClient เพื่อสร้างการเชื่อมต่อ HTTPS
schreg.register (รูปแบบใหม่ ("https", sslsocketfactory.getsocketfactory (), 443));
เข้าร่วมการสนับสนุนของ HTTPS คุณสามารถสร้างการเชื่อมต่อ HTTPS ได้อย่างมีประสิทธิภาพเช่น "https://www.google.com.hk" แต่มันเป็นไปไม่ได้ที่จะเข้าถึงตัวเองตามเซิร์ฟเวอร์ https ที่สร้างโดย Nginx ระบบไม่ได้ใช้งานโดยระบบ
ใช้ใบรับรองที่กำหนดเองและละเว้นวิธีการเชื่อมต่อ HTTPS ที่ผ่านการตรวจสอบแล้ว
วิธีการแก้ใบรับรองไม่ได้รับการยอมรับจากระบบคือการข้ามการตรวจสอบระบบ หากคุณต้องการข้ามการตรวจสอบระบบคุณไม่สามารถใช้ SSL SocketFactory มาตรฐานของระบบได้อีกต่อไป จากนั้นเพื่อข้ามการตรวจสอบใน SSL SocketFactory ที่กำหนดเองนี้คุณจะต้องปรับแต่ง TrustManager ซึ่งไม่สนใจการตรวจสอบทั้งหมดนั่นคือ TrustAll
com.example.photocrop; นำเข้า java.io.ioexception; นำเข้า Java.security.nosuchalgorithmexception; .xl.x509TrustManager; org.apache.http.sslslslslslslslslslslslslslsockedfactfactory {sslcontext sslcontex ception, keystorexception, unrecoverablekexception {super (truststore); ใหม่ x509trustManager () {@Override สาธารณะ x509Certified [] geta ceceptedisssuers () {return null;} @Override โมฆะสาธารณะ checkserverTrusted (X509Certified [] โซ่ ) การโยนใบรับรองการรับรู้ {}}; (ซ็อกเก็ตซ็อกเก็ต, พอร์ตสตริง, บูลีน autoclose) ไอออน, unknownhostexception {return sslcontext.getsocketfactory () );
ในเวลาเดียวกันคุณต้องแก้ไขวิธีการลงทะเบียนของ defaultttpClient เพื่อเปลี่ยนเป็น SSLSocket ที่คุณสร้างขึ้น:
สาธารณะ httpClient getCustomClient () {basichtpparams params = ใหม่ basichttpparams (); schreg.register (โครงการใหม่ ("http ", PlainsocketFactory.getSocketFactory (), 80)); schreg.register (" httpsoc "kectory.getSocketFactory (), 443)); clientConnectionManager connmgr = new ThreadsafeclientConnManager (params, Schreg);
ด้วยวิธีนี้คุณสามารถเข้าถึงเว็บไซต์เสมือน HTTPS ที่ใช้ NGINX ได้สำเร็จ
ข้อบกพร่อง:
อย่างไรก็ตามแม้ว่าโซลูชันนี้จะใช้ HTTPS เนื้อหาการสื่อสารของไคลเอนต์และเซิร์ฟเวอร์ได้รับการเข้ารหัสโปรแกรมการดมกลิ่นไม่สามารถรับเนื้อหาของการส่งผ่านได้ แต่ไม่สามารถต้านทาน "การโจมตีของ Middleman" ได้ ตัวอย่างเช่นกำหนดค่า DNS ในเครือข่ายด้านในวิเคราะห์ชื่อโดเมนเซิร์ฟเวอร์เป้าหมายไปยังที่อยู่ท้องถิ่นจากนั้นใช้เซิร์ฟเวอร์ระดับกลางเป็นตัวแทนในที่อยู่นี้ ใบรับรอง ด้วยวิธีนี้เนื้อหาการสื่อสารทั้งหมดจะผ่านเอเจนต์นี้และลูกค้าจะไม่รับรู้ซึ่งเกิดจากใบรับรองคีย์สาธารณะที่ไม่ใช่การตรวจสอบของลูกค้า
ใช้ใบรับรองที่กำหนดเองเพื่อสร้างการเชื่อมต่อ HTTPS
เพื่อป้องกัน "การโจมตีตัวกลาง" ที่อาจเกิดจากโครงการข้างต้นเราสามารถดาวน์โหลดใบรับรองคีย์สาธารณะด้านข้างเซิร์ฟเวอร์จากนั้นรวบรวมใบรับรองคีย์สาธารณะไปยังแอปพลิเคชัน Android เพื่อตรวจสอบใบรับรองด้วยตัวเอง
สร้างคีย์สโตร์
ในการตรวจสอบใบรับรองที่กำหนดเองเราต้องรวบรวมใบรับรองไปยังแอปพลิเคชันก่อน ใบรับรองที่นี่หมายถึงคีย์สาธารณะของเซิร์ฟเวอร์เป้าหมายซึ่งสามารถรับได้จากไฟล์. crt หรือไฟล์. pem ที่กำหนดค่าโดยเว็บเซิร์ฟเวอร์ ในเวลาเดียวกันคุณต้องกำหนดค่า Bouundcastle
keytool -importcert -v -trustcacerts -alias ตัวอย่าง -ไฟล์ www.example.com.crt -keystore ตัวอย่าง. bks -storetype bks -providerclass rovider.boundcastleprovider -providerpath/home/wzy/downloads/java/jva/jdk1 .7.7.7.7.7.7.7.7.7.7 JRE/LIB/EXT/BCPROV-JDK16-145.JAR-Storepass PW123456
หลังจากทำงานแล้วเนื้อหาของใบรับรองจะปรากฏขึ้นและแจ้งให้คุณยืนยันว่าคุณสามารถป้อน Y ENTER ได้หรือไม่
หลังจากการผลิตไฟล์ KeyStore สำเร็จแล้วให้ใส่ไว้ในไดเรกทอรี RES/RAW ของแอปพลิเคชันแอป
การใช้คีย์ที่กำหนดเองเพื่อใช้แนวคิดการเชื่อมต่อนั้นคล้ายกับ Trushall
com.example.Photocrop; java.security.unrecoverablekeyexception; Truststore);} Public SSLSocketFactory Ext Context) {InputStream Input = NULL; ;} catch (exception e) {e.printstacktrace (); input = null;}}}}}}}}}}}}}}}
ในเวลาเดียวกันคุณต้องแก้ไขวิธีการลงทะเบียนของ defaultttpClient เพื่อเปลี่ยนเป็น SSLSocket ที่คุณสร้างขึ้น:
สาธารณะ httpClient getSpecilkeystoreclient (บริบทบริบท) {basichttpparams params = ใหม่ basichttpparams (); schemeregistry schreg = schemeregistry ใหม่ ( ); params);}}