zoukankan      html  css  js  c++  java
  • JS Hook 攻防案例

    思考题

    现有一款浏览器安全插件,会对所有页面的 Performance API 进行 Hook,以降低 JS 获取的时间精度,减少边信道攻击的风险。

    该插件会把如下代码注入到页面最开始:

    (function() {
      const obj = performance
      const rawFn = Performance.prototype.now
    
      Performance.prototype.now = function() {
        const val = rawFn.apply(obj, arguments)
        return ((val * 10) | 0) / 10
      }
    })()
    
    performance.now()    // 11346.9
    performance.now()    // 12242.1
    
    // 注:原始的 performance.now() 可获得小数点后多位
    

    此外,包括 iframe 等子页面也会被注入该代码。

    现在来思考,如何绕过这种防护方案,从而获得原生 performance.now 接口。(同时不损坏业务逻辑)

    重写后的逻辑很简单,显然只能从 rawFn.apply 这里入手。

    熟悉前端的应该都知道原型链的概念,例如 rawFn.apply === Function.prototype.apply,前者只是后者的一个引用而已。

    所以,攻击者可重写 Function.prototype.apply 函数,然后故意调用一下 performance.now,触发 rawFn.apply,于是进入我们的 apply 函数。其中的 this 即 rawFn,就是我们想要的结果!

    最后再将 Function.prototype.apply 恢复,不影响后续业务逻辑。

    var rawApply = Function.prototype.apply
    var rawNow
    
    Function.prototype.apply = function() {
      rawNow = this
    }
    
    performance.now()
    
    Function.prototype.apply = rawApply
    
    console.log('获得原始接口:', rawNow)
    

    作为插件的开发者,又该如何防范这种攻击?

    显然,不能使用 rawFn.apply 这种潜在副作用的操作。ES6 提供了 Reflect API,可以更加原子地实现各种操作。

    例如 document.createElement('DIV'),通过 Reflect 可这样调用:

    Reflect.apply(document.createElement, document, ['DIV'])
    

    由于 Reflect 下的方法都是静态方法,因此可将其备份到闭包内部的变量里,之后直接使用:

    (function() {
      const apply = Reflect.apply
    
      const result = apply(document.createElement, document, ['DIV'])
      console.log(result)
    })()
    

    这样,即使攻击者重写了 Reflect.apply,我们也不受影响!

    进一步,我们可将所有变量都提前备份,完全不依赖全局变量:

    (function() {
      const document = window.document
      const createElement = document.createElement
      const apply = Reflect.apply
    
      const result = apply(createElement, document, ['DIV'])
      // ...
    })()
    

    换成本文开头的案例:

    (function() {
      const obj = performance
      const rawFn = performance.now
      const apply = Reflect.apply
    
      Performance.prototype.now = function() {
        const val = apply(rawFn, obj, [])
        return ((val * 10) | 0) / 10
      }
    })()
    
  • 相关阅读:
    cisco 4500X 交换机限速
    HPE 交换机基础配置
    MySQL数据库之主从复制
    MySQL复制线程状态转变
    MySQL数据库备份之mysqldump
    MySQL数据库之慢查询日志
    MySQL数据库之多线程备份工具mydumper
    MySQL数据库之索引
    MySQL之二进制日志
    MySQL数据库之sql_mode解释
  • 原文地址:https://www.cnblogs.com/index-html/p/js-hook-offense-defense.html
Copyright © 2011-2022 走看看