Facebook登录协议逆向实战:从加密参数到完整流程解析(附Python代码)

Facebook登录协议逆向实战:从加密参数到完整流程解析(附Python代码)

最近在研究一些主流社交平台的登录机制,发现很多开发者对Facebook的登录流程既好奇又有些无从下手。毕竟作为全球最大的社交平台之一,它的安全机制相对复杂,但一旦理清脉络,其实并没有想象中那么神秘。今天我就把自己在实际逆向分析中的完整思路和代码实现分享出来,希望能给正在研究Web安全、协议逆向的中高级开发者一些实用的参考。

很多人一看到加密参数就头疼,尤其是像lgndimencpass这种看起来像是随机生成的字符串。但如果你有耐心一步步跟踪,会发现这些参数背后都有清晰的生成逻辑。这篇文章不会只停留在表面分析,我会带你深入到加密函数的扣取、参数固定化处理等实战细节,并且解决一个国内开发者经常遇到的棘手问题——Crypto.js的异步调用处理。

1. 登录页面初探与关键参数定位

当你打开Facebook的登录页面时,如果打开开发者工具查看网络请求,会发现几个关键的加密参数。这些参数并不是随意生成的,每个都有其特定的作用和生成方式。

首先来看lgndim参数。这个参数的名字看起来像是"login dimension"的缩写,实际上它确实与设备信息相关。如果你仔细观察它的值,会发现它通常以eyJ开头,这明显是Base64编码的JSON格式特征。

import base64
import json

# 示例lgndim值(已脱敏)
lgndim_encoded = "eyJ3IjoxMjgwLCJoIjo3MjAsImQiOjI0fQ=="

# 解码查看实际内容
decoded_bytes = base64.b64decode(lgndim_encoded)
decoded_str = decoded_bytes.decode('utf-8')
lgndim_data = json.loads(decoded_str)

print(f"解码后的lgndim数据: {lgndim_data}")

运行上面的代码,你会看到类似这样的输出:

解码后的lgndim数据: {'w': 1280, 'h': 720, 'd': 24}

这清楚地表明lgndim包含了窗口宽度(w)、高度(h)和色彩深度(d)。这些信息对于服务端识别客户端环境很有用,但更重要的是,它告诉我们Facebook在客户端收集了哪些设备信息。

注意:在实际逆向中,不要直接在控制台使用atob()解码,因为某些浏览器环境可能会限制这种操作。最好在Python中处理,这样更可控。

另一个关键参数是encpass,这是密码的加密形式。如果你在登录表单输入密码后查看网络请求,会发现原始密码被转换成了这个加密字符串。要找到它的生成位置,最有效的方法是在开发者工具中搜索关键词。

2. encpass加密逻辑深度解析

encpass的生成是Facebook登录安全的核心。通过全局搜索encpass或相关函数名,我们可以定位到加密发生的位置。在实际分析中,我发现加密调用通常出现在类似这样的代码中:

f.encryptPassword(d.keyId, d.publicKey, e.value, g)

让我们分解这个函数的四个参数:

  • d.keyId:密钥ID,标识使用哪套加密密钥
  • d.publicKey:公钥,用于非对称加密
  • e.value:用户输入的原始密码
  • g:时间戳,防止重放攻击

有趣的是,在同一个会话中,d.keyIdd.publicKey的值通常是固定的。这意味着我们不需要每次登录都重新获取这些值,可以在会话开始时一次性获取并复用。

那么这些值从哪里来呢?通过进一步分析,我发现它们被硬编码在首页的JavaScript中,或者通过某个初始化接口返回。一个实用的技巧是搜索公钥的片段值:

import re

def extract_key_from_html(html_content):
    """从HTML内容中提取公钥和keyId"""
    
    # 查找包含publicKey的script标签
    # Facebook通常将密钥信息放在一个特定的变量中
    pattern = r'publicKey["\']?\s*:\s*["\']([^"\']+)["\']'
    matches = re.findall(pattern, html_content, re.IGNORECASE)
    
    if matches:
        public_key = matches[0]
        print(f"找到公钥: {public_key[:50]}...")
    
    # 查找keyId
    keyid_pattern = r'keyId["\']?\s*:\s*["\']?(\d+)["\']?'
    keyid_matches = re.findall(keyid_pattern, html_content)
    
    if keyid_matches:
        key_id = keyid_matches[0]
        print(f"找到keyId: {key_id}")
    
    return public_key, key_id

# 实际使用中,你需要先获取登录页面的HTML
# html_content = requests.get('https://www.facebook.com').text
# public_key, key_id = extract_key_from_html(html_content)

这种方法的好处是,我们不需要执行JavaScript就能获取加密所需的参数,大大简化了后续的自动化流程。

3. 加密函数扣取与本地化实现

找到加密函数后,下一步就是把它"扣"下来,转换成可以在本地环境中运行的代码。Facebook使用的是标准的Web Crypto API,这对于前端开发者来说很熟悉,但在Node.js或Python环境中需要一些适配工作。

让我们看看encryptPassword函数内部的大致结构:

async function encryptPassword(keyId, publicKey, password, timestamp) {
    // 1. 导入公钥
    const key = await crypto.subtle.importKey(
        'spki',
        base64ToArrayBuffer(publicKey),
        {
            name: 'RSA-OAEP',
            hash: 'SHA-256'
        },
        false,
        ['encrypt']
    );
    
    // 2. 准备加密数据(密码+时间戳)
    const encoder = new TextEncoder();
    const data = encoder.encode(password + ':' + timestamp);
    
    // 3. 执行加密
    const encrypted = await crypto.subtle.encrypt(
        {
            name: 'RSA-OAEP'
        },
        key,
        data
    );
    
    // 4. 转换为Base64
    return arrayBufferToBase64(encrypted);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值