JS逆向入门实战:通达OA 2019登录密码SHA-1加密算法分析与Python复现

📅 2026/8/13 1:57:54
JS逆向入门实战:通达OA 2019登录密码SHA-1加密算法分析与Python复现
1. 项目概述与背景最近在整理企业级应用安全审计的案例时我又翻出了通达OA Office Anywhere 2019这个经典的靶场。很多刚接触JS逆向的朋友一上来就想搞那些大型电商或社交平台结果往往被复杂的混淆和反调试机制劝退。其实从一些成熟但架构相对传统的企业应用入手是理解前端加密逻辑、培养逆向手感绝佳的路径。通达OA作为国内广泛使用的办公自动化系统其2019版本的前端登录密码加密就是一个结构清晰、非常适合新手入门的逆向分析样本。它没有使用极度复杂的混淆但包含了完整的加密函数定位、算法还原、参数模拟等核心环节堪称“JS逆向三百例”中的标准示范课。这个项目要解决的问题很明确当我们面对一个系统的登录接口发现提交的密码是一串毫无规律的密文时我们如何从浏览器出发一步步追踪到生成这串密文的JavaScript代码并最终理解其加密原理甚至能够用Python或其他语言独立复现这个加密过程这不仅是为了“破解”在安全测试、数据对接、自动化脚本开发等合规场景下这种分析能力都至关重要。接下来我就以通达OA 2019为例带你完整走一遍这个流程我会把每个步骤的意图、可能遇到的坑以及我调试时用的“骚操作”都交代清楚。2. 逆向分析的核心思路与准备工作2.1 分析目标与工具选型我们的终极目标是独立实现通达OA 2019登录时密码字段的加密算法。具体表现为输入明文密码如“123456”能输出与浏览器发送请求时完全一致的密文。这需要我们先通过浏览器开发者工具捕捉到登录请求观察其数据格式尤其是密码参数通常叫PASSWORD或password的样子。然后以此为线索逆向寻找生成它的JavaScript代码。工欲善其事必先利其器。对于这类传统Web应用的分析我习惯用Chrome DevTools它足够强大。有几个关键功能会高频使用Network网络面板用于捕获登录请求查看请求载荷Payload。重点关注Form Data或Payload标签页下的内容。Sources源代码面板用于搜索、查看和调试JavaScript文件。全局搜索CtrlShiftF是定位关键词的神器。Console控制台面板用于执行JavaScript代码片段测试我们还原的加密函数。为什么不推荐用Fiddler或Burp Suite它们当然也能抓包但对于前端JS代码的动态调试和追踪浏览器自带的DevTools有着无可替代的便捷性。Burp更适合用于拦截、重放和修改HTTP请求属于另一层面的工具。注意在开始分析前请确保你有一个合法的、用于学习和测试的通达OA 2019测试环境。所有分析操作应仅限于你自己拥有权限的测试系统严格遵守法律法规切勿对任何未授权的系统进行测试。2.2 初步侦察网络请求抓取与特征观察首先我们打开通达OA 2019的登录页面通常是类似/login.html或/的地址。打开DevTools的Network面板并勾选“Preserve log”保留日志防止页面跳转后请求记录被清空。在登录框输入一个简单的测试密码比如test123点击登录。此时Network面板会立刻出现一个新的请求通常是向/logincheck.php或类似接口发起的POST请求。点击这个请求查看其Headers和Payload。以我手头的环境为例捕获到的请求关键信息如下请求URL:http://your-oa-server/general/logincheck.php请求方法: POST表单数据 (Form Data):UNAME: admin PASSWORD: 7c4a8d09ca3762af61e59520943dc26494f8941b这里UNAME是明文用户名而PASSWORD是一串40位的十六进制字符串。40位长度这强烈暗示了可能是SHA-1哈希算法的结果SHA-1输出正好是160位即40个十六进制字符。当然这只是一个假设需要代码验证。我们的任务就是找到把test123变成7c4a8d09ca3762af61e59520943dc26494f8941b的那段JavaScript代码。3. 加密函数定位与关键代码追踪3.1 基于关键词的全局搜索定位知道密码参数名是PASSWORD密文是40位十六进制串这给了我们明确的搜索线索。在DevTools的Sources面板点击左侧文件列表上方的“{}”图标格式化代码然后使用CtrlShiftF进行全局搜索。搜索关键词的选择有技巧直接搜索参数名搜索PASSWORD。但这个词可能在HTML、JS里出现很多次需要过滤。搜索可能的加密函数名既然怀疑是SHA-1可以搜索SHA1、sha1、encrypt、hash等。搜索特征常量有时算法会用到一些常量比如SHA-1的初始哈希值0x67452301等但这对新手要求略高。在通达OA 2019中最有效的方法是搜索PASSWORD。在搜索结果中我们不是漫无目的地看而是要找那些在JS文件里并且看起来在给PASSWORD赋值的代码行。很快我们可能会定位到一个类似下面的代码片段代码已做简化示意// 可能在某个 .js 文件中例如 login.js 或 common.js function do_login() { var username document.getElementById(UNAME).value; var password document.getElementById(PASSWORD).value; // 关键行这里对password进行了处理 document.getElementById(PASSWORD).value hex_sha1(password); // 然后提交表单 document.forms[0].submit(); }或者在表单的onsubmit事件处理函数中form action/general/logincheck.php methodpost onsubmitreturn checkForm(this);然后去找到checkForm函数里面也会有类似的加密逻辑。实操心得全局搜索时不要只看一眼就过。点击搜索结果跳转到对应文件后要查看上下文。看看这个PASSWORD是在哪里被定义的是谁修改了它的值。通常加密操作就发生在这个修改的地方。3.2 深入加密函数hex_sha1 的逆向找到了hex_sha1(password)这行代码就等于找到了加密的核心函数。接下来我们的目标就是找到hex_sha1这个函数的定义。继续使用全局搜索搜索function hex_sha1或hex_sha1 function。在通达OA 2019中这个SHA-1的实现通常是直接嵌入在一个公共JS文件里的比如/static/js/sha1.js或者直接写在某个大文件的头部。找到后你会看到一整套SHA-1算法的JavaScript实现。代码可能长这样function hex_sha1(s) { return binb2hex(core_sha1(str2binb(s), s.length * chrsz)); } function core_sha1(x, len) { ... } function str2binb(str) { ... } function binb2hex(binarray) { ... } // ... 以及其他辅助函数到了这一步很多新手会觉得大功告成直接把这一坨JS代码复制出来就完事了。其实这才是最容易出错的地方。你不能假设这个hex_sha1函数就是标准的、独立的SHA-1。你必须验证两件事它是否依赖外部变量或函数查看hex_sha1函数体内是否使用了在它外部定义的全局变量比如chrsz、hexcase等。这些变量的值必须一并获取。它的输入输出是否经过额外处理在通达OA的这个案例里hex_sha1看起来就是标准的SHA-1。但在其他系统里可能会在SHA-1前后进行Base64编码、拼接时间戳、加盐salt等操作。一定要在调用hex_sha1的上下文中确认传入的参数是不是纯粹的明文密码有没有被拼接其他字符串。验证方法很简单在Console面板里直接调用我们找到的hex_sha1函数。输入我们测试的密码test123看输出是否与抓包得到的密文7c4a8d09ca3762af61e59520943dc26494f8941b一致。// 在Console中测试 hex_sha1(test123); // 观察输出是否等于 7c4a8d09ca3762af61e59520943dc26494f8941b如果一致恭喜算法还原成功。如果不一致就要回头仔细检查上下文看密码在传入hex_sha1前是否被修改。4. 算法还原与Python代码实现4.1 分析JavaScript加密逻辑经过上一步的验证我们确认通达OA 2019的密码加密就是标准的SHA-1哈希没有额外的盐或混淆。其逻辑链条非常清晰获取用户输入的明文密码字符串。将该字符串直接传入自定义的hex_sha1函数。hex_sha1函数内部按标准SHA-1算法计算哈希值并返回40位的十六进制字符串。将这个十六进制字符串赋值给表单的PASSWORD字段随表单提交。标准SHA-1算法虽然自己实现起来有点复杂涉及位运算、循环位移等但幸运的是我们几乎不需要自己重写。我们的目标是用Python模拟这个加密过程而Python的标准库hashlib已经提供了成熟且高效的SHA-1实现。4.2 Python复现加密过程既然算法是标准SHA-1Python复现就非常简单了。但这里我想强调一个非常重要的细节也是很多人在跨语言实现加密时容易踩的坑字符串的编码Encoding。JavaScript的字符串通常是UTF-16吗不完全是。在涉及加密哈希时尤其是这种比较老派的、自己实现算法的JS代码它处理字符串的方式往往是基于字符串的字符码charCode。而Python的hashlib的update方法需要接收字节bytes而不是字符串str。那么JS的hex_sha1(test123)在计算时到底相当于对什么样的字节序列进行哈希呢在绝大多数没有指定特殊编码的Web场景下可以等价于对UTF-8编码的字节序列进行哈希。这是一个非常常见且安全的假设。因此我们的Python实现代码如下import hashlib def encrypt_password_oa(password): 模拟通达OA 2019前端密码加密 :param password: 明文密码字符串 :return: 40位小写十六进制SHA-1哈希值 # 1. 将字符串转换为utf-8编码的字节 password_bytes password.encode(utf-8) # 2. 创建sha1哈希对象并更新数据 sha1_obj hashlib.sha1() sha1_obj.update(password_bytes) # 3. 获取十六进制哈希值 encrypted_password sha1_obj.hexdigest() return encrypted_password # 测试 if __name__ __main__: plain_password test123 encrypted encrypt_password_oa(plain_password) print(f明文密码: {plain_password}) print(f加密后: {encrypted}) # 输出应该与浏览器捕获的一致: 7c4a8d09ca3762af61e59520943dc26494f8941b assert encrypted 7c4a8d09ca3762af61e59520943dc26494f8941b, 加密结果不匹配为什么一定要用utf-8编码这是为了确保与前端JavaScript行为一致。虽然JS内部是UTF-16但其charCodeAt等函数在处理ASCII范围内的字符如字母数字时与UTF-8编码的ASCII部分是完全兼容的。而对于SHA-1这种将输入视为字节流的算法使用UTF-8编码是Web领域的通用实践。如果你不放心可以在JS控制台和Python中同时对一个包含中文的密码进行加密测试来验证编码是否一致。踩坑记录我曾经遇到一个系统它的前端JS在计算哈希前居然用escape()函数对密码进行了编码这会导致空格变成%20加号变成%2B。如果你用Python的hashlib.sha1(password.encode(utf-8))计算结果肯定对不上。这时就需要在Python里用urllib.parse.quote来模拟escape()的行为。好在通达OA 2019没有这个“骚操作”。5. 逆向过程中的常见问题与深度排查技巧即使是一个简单的SHA-1逆向在实际操作中也可能遇到各种问题。下面我总结了一个排查清单覆盖了从入门到进阶可能遇到的坑。5.1 问题一搜索不到明显的加密函数调用现象全局搜索PASSWORD、encrypt、SHA1都找不到明显的加密代码行。排查思路检查表单提交方式可能不是通过onsubmit而是通过按钮的onclick事件触发了某个JavaScript函数在这个函数里完成了加密和Ajax提交。搜索onclick或按钮的ID/Name。检查是否被混淆虽然通达OA 2019没有但很多现代应用会对JS进行混淆。代码可能变成ab[c](d)这种形式。这时搜索PASSWORD可能只能找到字符串本身而找不到调用逻辑。你需要在Network面板找到登录请求的Initiator发起者列点击它可能直接跳转到发起这个请求的JS代码行。在do_login或类似函数入口处打上断点在Sources面板对应行号点击然后重新登录让代码执行暂停再单步调试F11一步步跟踪password变量的变化。检查是否在框架内如果系统使用了Vue、React等框架密码绑定和提交逻辑可能藏在组件和方法里。你需要熟悉框架的调试方式例如在Vue Devtools中查看组件数据。5.2 问题二加密结果与Python实现不一致现象成功找到了JS加密函数在Console里测试结果也与抓包一致但用Python实现的代码算出来的结果就是不对。排查步骤逐层验证验证基础用例先用一个简单密码如123456分别在JS Console和Python中计算。如果简单密码都对复杂密码不对问题可能出在编码如果简单密码就不对问题更根本。验证编码环节这是最常见的坑。在JS加密函数的第一行打上断点或者手动在函数开始时添加console.log(输入:, password, 类型:, typeof password);。看看传入的到底是什么。然后在Python里在调用encode之前也打印一下字符串。确保两者完全一致包括不可见字符。验证算法细节如果JS用的是自定义的、非标准的哈希算法比如魔改的SHA-1那么hashlib就不管用了。你需要仔细阅读JS算法代码理解其每一步操作填充、循环、位运算等然后用Python原样实现一遍。这个过程非常繁琐但也是JS逆向的精髓所在。对于通达OA我们确认它是标准SHA-1所以这步跳过。验证最终输出格式JS函数返回的是40位小写十六进制吗有没有可能是Base64在Console里捕获加密后的值观察其长度和字符集。Python的hexdigest()输出小写如果JS输出大写你需要用.lower()转换或者JS里可能有一个hexcase变量控制大小写。5.3 问题三加密依赖了动态参数加盐现象每次登录即使密码相同生成的密文也不同。或者密文长度远超40位。排查思路观察请求参数除了UNAME和PASSWORD查看登录请求是否还提交了其他参数比如token、nonce、timestamp、salt等。这些很可能被用于和密码拼接后再加密。分析加密函数输入在JS加密函数处打上断点不仅查看password还要查看函数内部是否拼接了其他变量。例如可能是hex_sha1(password salt)或hex_md5(timestamp password)。追踪动态参数来源如果发现了加盐需要找到这个salt或token是怎么生成的。通常它会在页面加载时由后端渲染到HTML中如一个隐藏的input标签或者通过一个前置的Ajax请求获取。你需要用同样的思路去逆向生成这个动态参数的JS代码。通达OA 2019的总结它属于最简单的情况——无盐、静态、标准哈希。这让我们可以把重点放在理解逆向分析的完整流程上而不是陷入复杂的算法对抗。6. 逆向分析的进阶思考与防御视角通过这个简单的案例我们走完了一个完整的JS逆向流程。但作为安全研究者或开发者我们不能只停留在“能逆向”的层面更要思考背后的安全问题。6.1 从攻击者视角看这种加密的弱点通达OA 2019仅使用前端SHA-1加密密码存在几个明显弱点哈希而非加密SHA-1是哈希算法不可逆但它是公开的、确定性的。相同的密码永远产生相同的哈希值。无盐Salt这是最大的问题。攻击者可以预先计算一个巨大的“彩虹表”里面包含海量常用密码及其SHA-1哈希值。一旦从数据库或网络流量中拿到这个哈希直接查表就能瞬间得到明文密码。7c4a8d09ca3762af61e59520943dc26494f8941b在彩虹表里一查立刻就知道是test123。前端加密意义有限前端加密无法替代HTTPS。它在传输过程中可以防止密码明文被直接窥视但如果网络层本身不安全比如HTTP协议攻击者依然可以轻松截获请求并重放Replay Attack因为密文本身就可以作为登录凭证。前端加密的主要作用是避免密码在传输中因明文而意外泄露例如被浏览器历史记录、日志无意记录但无法抵御主动攻击。6.2 从开发者视角看如何改进如果我们是OA系统的开发者应该如何设计更安全的密码处理方案必须使用HTTPS这是底线。在HTTPS加密通道下即使前端不加密密码明文传输也是安全的。前端加密变成了锦上添花而非安全依赖。后端进行强哈希加盐前端可以做一次哈希像通达OA这样但后端在存储前必须再做一次加盐哈希。盐Salt应该是每个用户独立、足够长的随机字符串。推荐使用像bcrypt、scrypt或Argon2这样的密码哈希函数它们设计得计算缓慢能有效抵抗彩虹表和暴力破解。即使前端哈希值泄露攻击者也无法直接用其登录因为后端还会用不同的盐再哈希一次也极难反向破解出原密码。引入动态挑战值可以考虑引入类似CSRF Token的机制。登录时后端先返回一个随机数Nonce前端将密码哈希后再与这个Nonce进行某种计算如HMAC将结果提交。后端用同样的Nonce进行验证。这样每次登录的密文都不同有效防止重放攻击。避免在前端实现核心加密逻辑核心的、带盐的哈希运算应在后端完成。前端可以承担一些轻量的、不涉及密钥的预处理工作。6.3 逆向分析技能的合规应用最后强调一下这项技能的合规用途这远比“破解”更重要安全审计与渗透测试授权范围内帮助企业发现自身系统的安全漏洞如弱加密、逻辑缺陷等。自动化测试与数据对接在需要模拟用户登录进行自动化操作如数据采集、巡检时理解加密流程是编写脚本的前提。第三方系统集成当需要与一个已有系统进行数据打通而对方文档不全时逆向分析可以帮你弄清楚接口的调用方式。学习与研究就像我们这次做的一样通过分析经典案例深入理解Web安全机制、加密算法应用和前后端交互逻辑。通过“通达OA 2019密码加密”这个麻雀虽小五脏俱全的案例我希望你掌握的不仅仅是一个SHA-1的还原而是一套通用的JS逆向分析方法论从抓包观察、关键词搜索、断点调试、逻辑分析到代码复现和验证。这套方法稍加变通就能应用到更多、更复杂的场景中去。记住耐心和细致是逆向分析中最宝贵的品质每一个细节都可能成为突破的关键。