乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      WebSocket數(shù)據(jù)加密——AES與RSA混合加密

       hncdman 2022-05-13

        前言

        之前在寫“一套簡單的web即時(shí)通訊”,寫到第三版的時(shí)候沒什么思路,正好微信公眾號(hào)看到一篇講API交互加密,于是就自己搞了一套AES與RSA混合加密,無意中產(chǎn)生應(yīng)用在WebSocket想法,好在思路都差不多,稍微改動(dòng)一下就能實(shí)現(xiàn),特意寫這篇博客記錄下來

        WebSocket是HTML5 開始提供的一種瀏覽器與服務(wù)器進(jìn)行全雙工通訊的網(wǎng)絡(luò)技術(shù),屬于應(yīng)用層協(xié)議。它基于 TCP 傳輸協(xié)議,并復(fù)用 HTTP 的握手通道。

        1、建立連接,客戶端通過 HTTP 請(qǐng)求與服務(wù)端協(xié)商升級(jí)協(xié)議。協(xié)議升級(jí)完成后,后續(xù)的數(shù)據(jù)交換則遵照 WebSocket 的協(xié)議。

        2、數(shù)據(jù)交換,建立連接后,后續(xù)的操作通過TCP協(xié)議以數(shù)據(jù)幀的格式傳輸交換。

        通過TCP進(jìn)行數(shù)據(jù)交換,不像http請(qǐng)求,websocket數(shù)據(jù)交換在瀏覽器上使用開發(fā)者工具(F12)是看不到數(shù)據(jù),但使用抓包軟件仍然可以獲取到這些TCP傳輸數(shù)據(jù),例如Charles和Fiddler等,以明文的方式直接傳輸很容易被第三方監(jiān)聽,因此,我覺得是有必要的

        前面我們實(shí)現(xiàn)了一套AES與RSA混合加密(詳情請(qǐng)戳:前后端API交互數(shù)據(jù)加密——AES與RSA混合加密完整實(shí)例),我們現(xiàn)在用它實(shí)現(xiàn)一下WebSocket數(shù)據(jù)加密

        思路、代碼

        工具類我們直接用之前API加密那一套就行,操作也與之前的API加密類似,發(fā)送前加密、收到數(shù)據(jù)后解密再交給業(yè)務(wù)處理,有個(gè)地方要注意的是,我們?cè)谶M(jìn)行消息轉(zhuǎn)發(fā)時(shí),要用的是接收方的前端公鑰進(jìn)行加密

        按照我們目前的規(guī)則,項(xiàng)目啟動(dòng)后生成后端密鑰對(duì),訪問登錄頁面時(shí)響應(yīng)后端公鑰給前端,前端保存到后端RSA公鑰并存到sessionStorage,每個(gè)頁面都引入頭部head.html(使用thymeleaf的<script th:replace="head::static"></script>),在head里面獲取前端RSA公鑰密碼、AES的key,并放到window,這些都跟之前的一樣,不需要改變,需要改動(dòng)的是下面這些:

        建立WebSocket連接時(shí),將當(dāng)前用戶的前端公鑰發(fā)送到后端,后端進(jìn)行Map保存

      復(fù)制代碼

      //判斷當(dāng)前瀏覽器是否支持WebSocketif ('WebSocket' in window) {    //因?yàn)槭莡rl的方式傳值,公鑰中的/需要進(jìn)行轉(zhuǎn)換一下,傳到后端再轉(zhuǎn)回來(PS:因?yàn)樯傻墓€里是不存在","的,所以這里轉(zhuǎn)成逗號(hào))
          websocket = new WebSocket("ws://localhost:10086/websocket/" + userId + "/" + window.jsPublicKey.replace(/\//g,","));
      } else {
          console.error("不支持WebSocket");
      }

      復(fù)制代碼

      復(fù)制代碼

      /**
       * WebSocket服務(wù) */@Component
      @ServerEndpoint(value = "/websocket/{userId}/{publicKey}", configurator = MyEndpointConfigure.class)public class WebSocketServer {    //省略其他代碼  
      
          /**
           * 登錄用戶的前端公鑰Map集合(其實(shí)應(yīng)該放在Redis)     */
          private static Map<Session, String> loginPublicKeyList = new HashMap<Session, String>();    /**
           * 連接建立成功調(diào)用的方法     */
          @OnOpen    public void onOpen(Session session, @PathParam("userId") String userId, @PathParam("publicKey") String publicKey) {        //省略其他代碼        //設(shè)置前端公鑰,因?yàn)槭莡rl的方式傳值,公鑰中的/需要進(jìn)行轉(zhuǎn)換一下,傳到后端再轉(zhuǎn)回來,然后將每個(gè)用戶的前端公鑰存儲(chǔ)起來
              loginPublicKeyList.put(session,publicKey.replaceAll(",", "/"));
      
          }
      }

      復(fù)制代碼

        前端發(fā)送前加密

      復(fù)制代碼

      //發(fā)送消息function send(but) {    //業(yè)務(wù)操作不變,省略代碼
      
          //先加密
          let aesKey = aesUtil.genKey();
          let data = {
              data: aesUtil.encrypt(JSON.stringify({            "type": "1",            "toUser": {"userId": toUserId},            "fromUser": {"userId": fromUserId},            "message": message,            "date": nowTime
              }), aesKey),//AES加密后的數(shù)據(jù)
              aesKey: rsaUtil.encrypt(aesKey, sessionStorage.getItem('javaPublicKey')),//后端RSA公鑰加密后的AES的key
              publicKey: window.jsPublicKey//前端公鑰    };
          websocket.send(JSON.stringify(data));    //業(yè)務(wù)操作不變,省略代碼}

      復(fù)制代碼

        后端收到后先解密

      復(fù)制代碼

      /**
           * 服務(wù)器接收到客戶端消息時(shí)調(diào)用的方法     */
          @OnMessage    public void onMessage(String message, Session session) {        try {            //jackson
                  ObjectMapper mapper = new ObjectMapper();            //jackson 序列化和反序列化 date處理
                  mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
                  mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);            //JSON字符串轉(zhuǎn) HashMap
                  HashMap map = mapper.readValue(message, HashMap.class);            //先解密
                  String data = (String) map.get("data");
                  String aesKey = (String) map.get("aesKey");            //后端私鑰解密的到AES的key
                  byte[] plaintext = RsaUtil.decryptByPrivateKey(Base64.decodeBase64(aesKey), RsaUtil.getPrivateKey());
                  aesKey = new String(plaintext);            //RSA解密出來字符串多一對(duì)雙引號(hào)
                  aesKey = aesKey.substring(1, aesKey.length() - 1);            //AES解密得到明文data數(shù)據(jù)
                  String decrypt = AesUtil.decrypt(data, aesKey);            //JSON字符串轉(zhuǎn) HashMap
                  HashMap hashMap = mapper.readValue(decrypt, HashMap.class);            //得到hashMap,下面的業(yè)務(wù)操作跟前面的一樣,這里就不貼出來了
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }

      復(fù)制代碼

        后端發(fā)送之前先加密,這里要用消息接收方的前端公鑰進(jìn)行加密

      復(fù)制代碼

      /**
           * 封裝一個(gè)send方法,發(fā)送消息到前端     */
          private void send(Session session, String message) {        try {            //發(fā)送前加密            //每次響應(yīng)之前隨機(jī)獲取AES的key,加密data數(shù)據(jù)
                  String key = AesUtil.getKey();
                  String data = AesUtil.encrypt(message, key);            //用前端的公鑰來解密AES的key,并轉(zhuǎn)成Base64,注意:這里需要用接收方的前端公鑰進(jìn)行加密,從loginPublicKeyList集合獲取
                  String aesKey = Base64.encodeBase64String(RsaUtil.encryptByPublicKey(key.getBytes(), loginPublicKeyList.get(session)));            //發(fā)送過去的是AES加密后的data,跟RSA加密后的aesKey
                  session.getBasicRemote().sendText("{\"data\":\"" + data + "\",\"aesKey\":\"" + aesKey + "\"}");
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }

      復(fù)制代碼

        前端收到消息后先解密

      復(fù)制代碼

      //接收到消息的回調(diào)方法websocket.onmessage = function (event) {
          let data = eval("(" + event.data + ")");    //先解密
          let msgObj = aesUtil.decrypt(data.data, rsaUtil.decrypt(data.aesKey, window.jsPrivateKey));    
          //業(yè)務(wù)操作不變,省略代碼};

      復(fù)制代碼

        效果演示  

        按照程序流程:

        前端加密前、加密后

       

        后端解密前、解密后

        后端加密前、加密后

        前端解密前、解密后

         完整頁面演示:

        好友上線在線系統(tǒng)通知沒有問題

        聊天沒有問題

        后記

        WebSocket的加密就先記錄到這里,其他的后面再補(bǔ)充

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多