攻击者是如何从JavaScript文件中窃取敏感信息的
字数 1162 2025-08-27 12:33:31

JavaScript文件中敏感信息的安全风险与防护措施

1. 问题概述

在JavaScript文件中存储敏感信息(如API密钥、用户凭证等)是一种极其危险的做法,主要原因包括:

  • JavaScript文件是公开可访问的
  • 全局作用域中的变量可被任何包含该脚本的网站访问
  • 攻击者可以通过多种方式窃取这些信息

2. 常见错误示例

2.1 全局变量存储敏感信息

var api_key = '1391f6bd2f6fe8dcafb847e0615e5b29';
var profileInfo = apiCall('getProfile', api_key, 'all');

这种写法将API密钥暴露在全局作用域中,任何包含此脚本的页面都能访问api_key变量。

3. 作用域与变量声明

3.1 作用域类型

  1. 全局作用域:变量成为window对象的属性
  2. 函数作用域:使用var在函数内声明的变量
  3. 块级作用域:ES6引入的letconst

3.2 变量声明方式

关键字 作用域 可重新赋值 提升
var 函数作用域
let 块级作用域
const 块级作用域

3.3 严格模式

使用"use strict"可以防止意外创建全局变量:

"use strict";
var test1 = 'arka'; // 正常工作
test2 = 'kapı';     // 抛出ReferenceError

4. 保护变量的尝试与局限

4.1 立即调用函数表达式(IIFE)

(function() {
    "use strict";
    var privateVar = 'Secret value';
})();
console.log(privateVar); // ReferenceError

虽然IIFE可以避免污染全局命名空间,但不能真正保护敏感数据

5. 攻击者窃取敏感信息的方法

5.1 覆盖原生函数

window.fetch = (url, options) => {
    console.log(`URL: ${url}, data: ${options.body}`);
};

(function() {
    "use strict";
    var api_key = "1391f6bd2f6fe8dcafb847e0615e5b29";
    fetch('/api/v1/getusers', {
        method: "POST",
        body: "api_key=" + api_key
    });
})();

攻击者可以覆盖fetch函数来拦截包含敏感数据的请求。

5.2 定义Setter和Getter

Object.prototype.__defineSetter__('api_key', function(value) {
    console.log(value);
    return this._api_key = value;
});

Object.prototype.__defineGetter__('api_key', function() {
    return this._api_key;
});

(function() {
    "use strict";
    let options = {};
    options.api_key = "1391f6bd2f6fe8dcafb847e0615e5b29";
    anotherAPICall(options);
})();

通过定义全局setter,可以记录所有赋值给特定属性名的值。

5.3 自定义迭代器

Array.prototype[Symbol.iterator] = function() {
    let arr = this;
    let index = 0;
    console.log(arr);
    return {
        next: function() {
            return {
                value: arr[index++],
                done: index > arr.length
            }
        }
    }
};

(function() {
    let secretArray = ["this", "contains", "an", "API", "key"];
    for(let element of secretArray) {
        doSomething(element);
    }
})();

通过自定义数组迭代器,可以访问数组中的所有元素。

6. 最佳实践建议

  1. 永远不要将敏感数据硬编码在JavaScript文件中
  2. 从服务器动态获取敏感数据
    • 使用安全的API端点
    • 实现适当的身份验证和授权机制
    • 使用短期有效的令牌而非长期有效的密钥
  3. 使用服务器端会话管理而非客户端存储敏感信息
  4. 实施CSP(内容安全策略)限制脚本来源
  5. 使用HTTP-only、Secure标志的Cookie存储会话标识符

7. 替代方案

当确实需要将某些配置信息传递给客户端时:

  1. 使用服务器生成的临时令牌而非永久密钥
  2. 通过meta标签传递非敏感配置
    <meta name="app-config" content="some-non-sensitive-config">
    
  3. 使用加密的Web存储(但仍需谨慎)

8. 总结

在客户端JavaScript中保护敏感数据本质上是不安全的,因为:

  • 浏览器环境是完全开放的
  • 任何包含脚本的上下文都可以被操纵
  • 有多种技术可以绕过看似安全的封装

唯一可靠的安全策略是完全不将敏感数据暴露给客户端,所有敏感操作都应通过安全的服务器端API进行。

JavaScript文件中敏感信息的安全风险与防护措施 1. 问题概述 在JavaScript文件中存储敏感信息(如API密钥、用户凭证等)是一种极其危险的做法,主要原因包括: JavaScript文件是公开可访问的 全局作用域中的变量可被任何包含该脚本的网站访问 攻击者可以通过多种方式窃取这些信息 2. 常见错误示例 2.1 全局变量存储敏感信息 这种写法将API密钥暴露在全局作用域中,任何包含此脚本的页面都能访问 api_key 变量。 3. 作用域与变量声明 3.1 作用域类型 全局作用域 :变量成为window对象的属性 函数作用域 :使用 var 在函数内声明的变量 块级作用域 :ES6引入的 let 和 const 3.2 变量声明方式 | 关键字 | 作用域 | 可重新赋值 | 提升 | |--------|----------|------------|------| | var | 函数作用域 | 是 | 是 | | let | 块级作用域 | 是 | 否 | | const | 块级作用域 | 否 | 否 | 3.3 严格模式 使用 "use strict" 可以防止意外创建全局变量: 4. 保护变量的尝试与局限 4.1 立即调用函数表达式(IIFE) 虽然IIFE可以避免污染全局命名空间,但 不能真正保护敏感数据 。 5. 攻击者窃取敏感信息的方法 5.1 覆盖原生函数 攻击者可以覆盖 fetch 函数来拦截包含敏感数据的请求。 5.2 定义Setter和Getter 通过定义全局setter,可以记录所有赋值给特定属性名的值。 5.3 自定义迭代器 通过自定义数组迭代器,可以访问数组中的所有元素。 6. 最佳实践建议 永远不要将敏感数据硬编码在JavaScript文件中 从服务器动态获取敏感数据 : 使用安全的API端点 实现适当的身份验证和授权机制 使用短期有效的令牌而非长期有效的密钥 使用服务器端会话管理 而非客户端存储敏感信息 实施CSP(内容安全策略) 限制脚本来源 使用HTTP-only、Secure标志的Cookie 存储会话标识符 7. 替代方案 当确实需要将某些配置信息传递给客户端时: 使用服务器生成的临时令牌 而非永久密钥 通过meta标签传递非敏感配置 : 使用加密的Web存储 (但仍需谨慎) 8. 总结 在客户端JavaScript中保护敏感数据本质上是不安全的,因为: 浏览器环境是完全开放的 任何包含脚本的上下文都可以被操纵 有多种技术可以绕过看似安全的封装 唯一可靠的安全策略是 完全不将敏感数据暴露给客户端 ,所有敏感操作都应通过安全的服务器端API进行。