首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> JSP 程式設計 >> 關於JSP

QQ 聯系人導入方案(下):JSP 前端頁面與 RSA 加密實現

     編輯:關於JSP

前端頁面流程

  1. 用戶訪問 JSP 頁面,後端預先獲取 RSA 公鑰、域名、時間戳 (ts) 並放入 request 域。
  2. 頁面載入時顯示驗證碼圖片 (code.jsp)。
  3. 用戶輸入 QQ 號、密碼、驗證碼,點擊提交。
  4. onsubmit 觸發 JS ras():讀取公鑰,將 密碼\nTS\n 進行 RSA 加密,結果 Base64 編碼填入隱藏域 p;原密碼框置為同長度掩碼(如「0000」);提交表單至 action.jsp。
  5. 後端 action.jsp 接收參數,調用 Java 端登錄邏輯(見上篇),獲取聯系人並展示或存儲。

JSP 頁面完整代碼

<%@ page language="java" pageEncoding="UTF-8"%>
<%@page import="qq.QQContactsService"%>
<%@page import="qq.RSAInfo"%>
<%
    QQContactsService service = QQContactsService.getInstance();
    RSAInfo rsa = service.getRSAInfo(); // 獲取公鑰、域名、ts
    request.setAttribute("domain", rsa.getDomain());
    request.setAttribute("publicKey", rsa.getPublicKey());
    request.setAttribute("ts", rsa.getTs());
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
    <title>QQ Import Contact</title>
    <script language="JavaScript" src="js/auth.js"></script> <!-- 包含 RSA 加密實現 -->
</head>
<body>
<form name="form1" action="action.jsp" onsubmit="ras()" method="post">
    QQ: <input type="text" name="uin" id="uin"><br>
    PWD: <input type="password" name="pp" id="pp"><br>
    verify: <input type="text" name="verifycode" id="verifycode">
    <img src="code.jsp" id="captchaImg"><br>
    <input type="hidden" name="domain" id="domain" value="${domain}">
    <input type="hidden" name="ts" id="ts">
    <input type="hidden" name="starttime" id="starttime">
    <input type="hidden" name="p" id="p"> <!-- 加密後密碼 -->
    <input type="submit" name="login" value="登錄導入">
</form>

<script type="text/javascript">
var $ = function(id) { return document.getElementById(id); };

function ras() {
    var publicKey = "${publicKey}"; // JSP EL 輸出
    var rsa = new RSAKey(); // auth.js 中定義
    rsa.setPublic(publicKey, "10001"); // 指數固定為 0x10001
    var ts = "${ts}";
    // 加密:密碼 + '\n' + ts + '\n'
    var encrypted = rsa.encrypt($("pp").value + '\n' + ts + '\n');
    if (encrypted) {
        $("p").value = hex2b64(encrypted); // 轉 Base64
    }
    // 掩碼原密碼,防止明文傳輸
    var mask = "";
    for (var i=0; i<$("pp").value.length; i++) mask += "0";
    $("pp").value = mask;
    $("starttime").value = new Date().getTime();
    return true; // 允許表單提交
}
</script>
</body>
</html>

JavaScript RSA 實現 (js/auth.js 關鍵部分)

採用 jsbn 庫(MIT 許可),核心類:RSAKey、BigInteger、Base64 工具。頁面只需引入該 JS 文件即可使用 new RSAKey().setPublic(modulus, exponent).encrypt(data)。

Java 後端服務類設計

package qq;

public class RSAInfo {
    private String domain;      // 登錄提交域名,如 m126.mail.qq.com
    private String publicKey;   // RSA 公鑰模數 (16進制字符串)
    private String ts;          // 時間戳
    // getter/setter 省略
}

public class QQContactsService {
    private static QQContactsService instance = new QQContactsService();
    public static QQContactsService getInstance() { return instance; }

    public RSAInfo getRSAInfo() {
        // 1. 訪問登錄頁面 https://mail.qq.com/cgi-bin/loginpage
        // 2. 解析 HTML 獲取公鑰、域名、ts(或從固定 JS 文件提取)
        // 3. 返回封裝對象
        // 注意:騰訊可能定期更換公鑰,需緩存並定時刷新
    }

    public List loginAndFetchContacts(String uin, String encryptedPwd, String verifyCode, String ts, String domain) {
        // 使用 HttpClient 模擬登錄 POST,攜帶 Cookie
        // 登錄成功後訪問聯系人接口(可能為 JSON 或 HTML)
        // 解析並返回 Contact 列表
    }
}

驗證碼生成 code.jsp

<%@ page contentType="image/jpeg" import="java.awt.*,java.awt.image.*,javax.imageio.*,java.util.*" %>
<%
    response.setHeader("Cache-Control", "no-store");
    BufferedImage img = new BufferedImage(60, 20, BufferedImage.TYPE_INT_RGB);
    Graphics g = img.getGraphics();
    g.setColor(new Color(0xEE,0xEE,0xEE)); g.fillRect(0,0,60,20);
    g.setColor(Color.BLACK); g.drawRect(0,0,59,19);
    String code = "";
    for(int i=0;i<4;i++) code += (char)('0'+Math.random()*10);
    session.setAttribute("qq_verify_code", code);
    g.setColor(Color.RED); g.setFont(new Font("Arial", Font.BOLD, 16));
    g.drawString(code, 8, 15);
    g.dispose();
    ImageIO.write(img, "JPEG", response.getOutputStream());
%>

安全加固建議

  • HTTPS 全鏈路:登錄頁、提交接口、驗證碼圖片均強制 HTTPS。
  • 密碼不落地:前端加密後立即清空原密碼變量;後端驗證後不持久化明文/密文。
  • 驗證碼二次校驗:前端 JS 僅作體驗優化,後端 action.jsp 必須再次校驗驗證碼。
  • 限流與日誌:同 IP/同 QQ 短時間多次失敗封禁,記錄審計日志(脫敏)。
  • 遷移至 OAuth:騰訊開放平台提供 QQ 登錄/聯系人授權接口,徹底避免密碼處理風險。

總結

本方案通過「前端 RSA 加密 + 後端 HttpClient 模擬登錄」實現 QQ 聯系人導入,解決了密碼傳輸安全與動態參數獲取難題。但屬逆向工程方案,穩定性依賴騰訊前端邏輯不變。強烈建議正式項目申請 QQ 互聯 (OpenAPI) 官方授權,使用 OAuth 2.0 標準流程獲取聯系人,安全合規且長期穩定。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved