Report.py 里的 BuildReport 类里,并通过 -Y COMPILE_INFO -y BuildReport.log ...

页赣肪幢JavaScript 中的安全编码:10 个关键实践

引言

JavaScript 作为现代 Web 开发的核心语言,几乎无处不在——从简单的前端交互到复杂的 Node.js 后端应用。然而,正是这种广泛的应用使 JavaScript 成为攻击者的主要目标。本文旨在为开发者提供 10 个关键的安全编码实践,帮助构建更安全的 JavaScript 应用程序。我们将从最常见的跨站脚本攻击(XSS)开始,逐步深入到框架选择、编码规范、工具使用等多个层面,为您呈现一份全面的 JavaScript 安全编码指南。

正文内容

1. 防范跨站脚本攻击(XSS)

跨站脚本攻击(XSS)是 JavaScript 安全中最常见也最危险的问题之一。XSS 攻击的特殊之处在于它直接针对用户浏览器,攻击者可以利用它窃取会话信息、操纵页面内容甚至安装恶意软件。

要全面防范 XSS,应采取以下措施:

// 不安全的做法:直接插入未处理的用户输入

document.getElementById('output').innerHTML = userInput;

// 安全的做法:使用textContent而不是innerHTML

document.getElementById('output').textContent = userInput;

输入验证:对所有用户提供的数据进行严格验证,只接受预期的字符集。

输出编码:在将数据呈现到页面时进行适当的编码,确保特殊字符被转义。

内容安全策略(CSP):通过 CSP 头部限制可执行的脚本来源。

安全Cookie设置:为Cookie添加HttpOnly和Secure标志,防止通过JavaScript访问敏感Cookie。

2. 选择安全的JavaScript框架

现代前端框架如React、Angular和Vue.js都内置了自动输出编码的安全机制。这些框架通过虚拟DOM和其他安全机制,大大降低了XSS的风险。

然而,框架也提供了一些"逃生舱口"功能,如React的dangerouslySetInnerHTML和Angular的bypassSecurityTrustAs*系列方法。这些方法应尽量避免使用,除非确实必要且已采取其他安全措施。

3. 避免内联脚本

内联脚本(直接在HTML中编写的JavaScript)不仅难以维护,还会增加XSS的风险。最佳实践是将所有JavaScript代码放在独立的外部文件中,并通过CSP头部明确允许这些文件。

4. 启用严格模式

JavaScript的严格模式('use strict')通过限制某些危险语法和行为,帮助编写更安全的代码。严格模式的主要优势包括:

禁止意外创建全局变量

使eval和arguments更安全

禁止使用未来可能成为关键字的标识符

使this在全局函数中为undefined而非window对象

// 启用严格模式

'use strict';

// 在严格模式下,以下代码会抛出错误

undefinedVar = 10; // ReferenceError

5. 利用开源安全工具

开源社区提供了大量工具来帮助检测和预防JavaScript安全问题。以下是一些值得推荐的工具:

DOMPurify:用于净化HTML输入,防止XSS。

Retire.js:检查项目中使用的JavaScript库是否有已知漏洞。

npm audit/yarn audit:检查依赖项的安全问题。

Semgrep:静态代码分析工具,可检测多种安全问题。

ZAP:动态应用安全测试工具,但使用前需获得授权。

6. 明确区分文本和代码

在JavaScript中操作DOM时,必须明确区分应作为文本处理的内容和应作为代码执行的内容。使用innerText或textContent而非innerHTML来插入纯文本内容。

// 不安全的做法

element.innerHTML = userProvidedData;

// 安全的做法

element.textContent = userProvidedData;

7. 安全使用属性设置

当使用setAttribute设置元素属性时,只应使用安全的静态属性。避免将用户提供的数据用于动态属性如onclick或onmouseover。

安全属性示例包括:class, id, title, alt, value等。而on*系列事件处理属性则属于不安全属性。

8. 后端输入验证

前端输入验证虽能提升用户体验,但绝不能替代后端验证。攻击者可以轻松绕过前端验证,直接向后端发送恶意数据。

// 前端验证(仅用于用户体验)

function validateInput(input) {

return /^[a-zA-Z0-9]+$/.test(input);

}

// 后端也必须进行相同的验证

// (示例为伪代码,实际实现取决于后端语言)

app.post('/api/submit', (req, res) => {

if (!/^[a-zA-Z0-9]+$/.test(req.body.input)) {

return res.status(400).send('Invalid input');

}

// 处理合法输入...

});

9. 避免危险函数

JavaScript中有一些函数因其特性而特别危险,尤其是在处理用户输入时。这些函数包括:

eval():执行字符串作为代码

Function()构造函数:类似eval

setTimeout()/setInterval():使用字符串而非函数

document.write():可能覆盖整个文档

innerHTML/outerHTML:可能导致XSS

// 极其危险的做法

eval(userInput);

// 同样危险的变体

new Function(userInput)();

// 相对安全的做法

setTimeout(() => {

console.log('安全代码');

}, 1000);

10. 全面应用安全开发实践

JavaScript应用的安全不应局限于语言特性本身,还应包括全面的安全开发实践。这包括:

安全的系统开发生命周期(S-SDLC):将安全考虑融入整个开发过程。

参数化查询:防止SQL注入

加密:数据传输和存储加密

身份验证和授权:可靠的用户管理系统

依赖管理:定期更新第三方库

结论

JavaScript的安全编码是一个需要持续关注和学习的领域。从防范XSS攻击到选择合适的框架,从启用严格模式到利用安全工具,再到避免危险函数,每个环节都至关重要。安全不是一蹴而就的,而是需要在日常开发中不断实践和强化的习惯。

作为开发者,我们可以从今天开始,选择一两个最佳实践应用到当前项目中。随着经验的积累,逐步引入更多的安全措施,最终构建出既功能强大又安全可靠的JavaScript应用。记住,安全不是可选项,而是每个负责任开发者的基本职责。

通过知识共享和持续改进,我们可以让JavaScript生态不仅更加强大和高效,同时也更加安全。

import os os.environ['TF_ENABLE_ONEDNN_OPTS'] = '0' import numpy as np, pandas as pd, tensorflow as tf from sklearn.preprocessing import StandardScaler from sklearn.utils.class_weight import compute_class_weight from sklearn.model_selection import train_test_split from sklearn.metrics import (classification_report, roc_auc_score, f1_score, recall_score, precision_score) from tensorflow.keras.layers import (Input, LSTM, Dense, Dropout, BatchNormalization, Bidirectional, Concatenate, Attention) from tensorflow.keras.models import Model from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint from tensorflow.keras.optimizers import Nadam from bayes_opt import BayesianOptimization from imblearn.over_sampling import SMOTE from functools import partial # -------------------------------------------------- # 1. 读取数据 # -------------------------------------------------- data_path = r'C:\Users\Lenovo\Desktop\时间序列.xlsx' data = pd.read_excel(data_path) X = data.iloc[:, :7].values # 前 7 列特征 y_bin = data.iloc[:, 7].values # 第 8 列 0/1 异常标志 y_type_raw = data.iloc[:, 8].values # 第 9 列 1–5 磨损(异常样本) scaler = StandardScaler() X_scaled = scaler.fit_transform(X) # -------------------------------------------------- # 2. 滑窗 # -------------------------------------------------- time_steps = 8 def create_sequences(data_X, data_y, time_steps): X, y = [], [] for i in range(len(data_X) - time_steps + 1): X.append(data_X[i:i + time_steps]) y.append(data_y[i + time_steps - 1]) return np.array(X), np.array(y) X_seq, y_seq_bin = create_sequences(X_scaled, y_bin, time_steps) # -------------------------------------------------- # 3. 时序划分 # -------------------------------------------------- X_train, X_test, y_train_bin, y_test_bin = train_test_split( X_seq, y_seq_bin, test_size=0.2, shuffle=False, random_state=42) # -------------------------------------------------- # 4. SMOTE + 别权重(仅针对异常检测) # -------------------------------------------------- X_train_2d = X_train.reshape(X_train.shape[0], -1) X_train_res, y_train_res = SMOTE(random_state=42).fit_resample(X_train_2d, y_train_bin) X_train_res = X_train_res.reshape(-1, time_steps, X_train.shape[2]) classes = np.unique(y_train_res) weights = compute_class_weight('balanced', classes=classes, y=y_train_res) class_weight = dict(zip(classes, weights)) # -------------------------------------------------- # 5. 自定义 Focal Loss # -------------------------------------------------- def focal_loss_fixed(y_true, y_pred, gamma=2.0, alpha=0.8): eps = tf.keras.backend.epsilon() y_pred = tf.clip_by_value(y_pred, eps, 1 - eps) p_t = tf.where(tf.equal(y_true, 1), y_pred, 1 - y_pred) alpha_t = tf.where(tf.equal(y_true, 1), alpha, 1 - alpha) return -tf.reduce_mean(alpha_t * tf.pow(1 - p_t, gamma) * tf.math.log(p_t)) # -------------------------------------------------- # 6. 异常检测模型 # -------------------------------------------------- def build_bin_model(lstm1, lstm2, lstm3, dropout, lr, gamma, alpha): inputs = Input(shape=(time_steps, X_train_res.shape[2])) x = Bidirectional(LSTM(int(lstm1), return_sequences=True))(inputs) x = BatchNormalization()(x); x = Dropout(dropout)(x) x = LSTM(int(lstm2), return_sequences=True)(x) x = BatchNormalization()(x); x = Dropout(dropout)(x) att = Attention()([x, x]) x = Concatenate()([x, att]) x = LSTM(int(lstm3))(x) x = BatchNormalization()(x); x = Dropout(dropout)(x) outputs = Dense(1, activation='sigmoid')(x) model = Model(inputs, outputs) model.compile(optimizer=Nadam(learning_rate=lr, clipnorm=1.0), loss=partial(focal_loss_fixed, gamma=gamma, alpha=alpha), metrics=[tf.keras.metrics.AUC(name='auc'), tf.keras.metrics.Recall(name='recall')]) return model # -------------------------------------------------- # 7. 异常检测贝叶斯优化 # -------------------------------------------------- def bin_cv(lstm1, lstm2, lstm3, dropout, lr, batch_size, gamma, alpha): lstm1, lstm2, lstm3, batch_size = map(int, (lstm1, lstm2, lstm3, batch_size)) gamma, alpha, dropout, lr = float(gamma), float(alpha), float(dropout), float(lr) model = build_bin_model(lstm1, lstm2, lstm3, dropout, lr, gamma, alpha) es = EarlyStopping(monitor='val_recall', mode='max', patience=5, restore_best_weights=True, verbose=0) X_tr, X_val, y_tr, y_val = train_test_split( X_train_res, y_train_res, test_size=0.1, random_state=42, stratify=y_train_res) model.fit(X_tr, y_tr, epochs=30, batch_size=batch_size, verbose=0, validation_data=(X_val, y_val), class_weight=class_weight, callbacks=[es]) return max(model.history.history['val_recall']) pbounds_bin = {'lstm1': (64, 256), 'lstm2': (32, 128), 'lstm3': (16, 96), 'dropout': (0.1, 0.5), 'lr': (1e-4, 5e-3), 'batch_size': (16, 64), 'gamma': (1.5, 3.0), 'alpha': (0.7, 0.95)} bin_opt = BayesianOptimization(f=bin_cv, pbounds=pbounds_bin, random_state=42, verbose=2) bin_opt.maximize(init_points=6, n_iter=12) best_bin = bin_opt.max['params'] # -------------------------------------------------- # 8. 重新训练异常检测模型(去掉 batch_size) # -------------------------------------------------- best_bin_pop = best_bin.copy() best_bin_pop.pop('batch_size', None) final_bin_model = build_bin_model(**best_bin_pop) es_bin = EarlyStopping(monitor='val_recall', mode='max', patience=20, restore_best_weights=True, verbose=1) lr_bin = ReduceLROnPlateau(monitor='val_recall', mode='max', factor=0.5, patience=5, min_lr=1e-5) ckpt_bin = ModelCheckpoint('best_bin_model.keras', monitor='val_recall', mode='max', save_best_only=True, verbose=1) X_tr, X_val, y_tr, y_val = train_test_split( X_train_res, y_train_res, test_size=0.1, random_state=42, stratify=y_train_res) final_bin_model.fit(X_tr, y_tr, epochs=120, batch_size=int(best_bin['batch_size']), verbose=2, validation_data=(X_val, y_val), class_weight=class_weight, callbacks=[es_bin, lr_bin, ckpt_bin]) # -------------------------------------------------- # 9. 阈值搜索(最大 F1) # -------------------------------------------------- y_val_prob = final_bin_model.predict(X_val, verbose=0).ravel() ths = np.arange(0.05, 0.95, 0.02) best_th, best_f1 = 0.3, 0 for th in ths: ff = f1_score(y_val, (y_val_prob > th).astype(int)) if ff > best_f1: best_f1, best_th = ff, th print(f'最优阈值 = {best_th:.3f}, F1 = {best_f1:.4f}') # -------------------------------------------------- # 10. 构造异常样本多分数据集 # -------------------------------------------------- abn_mask = y_train_res == 1 X_train_abn = X_train_res[abn_mask] y_type_train = y_type_raw[np.where(y_train_res == 1)[0]] mask = ~pd.isna(y_type_train) X_train_abn, y_type_train = X_train_abn[mask], y_type_train[mask].astype(int) - 1 # 0-based num_classes = 5 # -------------------------------------------------- # 11. 多分模型 # -------------------------------------------------- def build_type_model(lstm1, lstm2, lstm3, dropout, lr): inputs = Input(shape=(time_steps, X_train_abn.shape[2])) x = Bidirectional(LSTM(int(lstm1), return_sequences=True))(inputs) x = BatchNormalization()(x); x = Dropout(dropout)(x) x = LSTM(int(lstm2), return_sequences=True)(x) x = BatchNormalization()(x); x = Dropout(dropout)(x) att = Attention()([x, x]) x = Concatenate()([x, att]) x = LSTM(int(lstm3))(x) x = BatchNormalization()(x); x = Dropout(dropout)(x) outputs = Dense(num_classes, activation='softmax')(x) model = Model(inputs, outputs) model.compile(optimizer=Nadam(learning_rate=lr, clipnorm=1.0), loss='sparse_categorical_crossentropy', metrics=['accuracy']) return model # -------------------------------------------------- # 12. 多分贝叶斯优化 # -------------------------------------------------- def type_cv(lstm1, lstm2, lstm3, dropout, lr, batch_size): lstm1, lstm2, lstm3, batch_size = map(int, (lstm1, lstm2, lstm3, batch_size)) dropout, lr = float(dropout), float(lr) model = build_type_model(lstm1, lstm2, lstm3, dropout, lr) es = EarlyStopping(monitor='val_accuracy', mode='max', patience=5, restore_best_weights=True, verbose=0) X_tr, X_val, y_tr, y_val = train_test_split( X_train_abn, y_type_train, test_size=0.1, random_state=42, stratify=y_type_train) model.fit(X_tr, y_tr, epochs=30, batch_size=batch_size, verbose=0, validation_data=(X_val, y_val), callbacks=[es]) return max(model.history.history['val_accuracy']) pbounds_type = {'lstm1': (64, 256), 'lstm2': (32, 128), 'lstm3': (16, 96), 'dropout': (0.1, 0.5), 'lr': (1e-4, 5e-3), 'batch_size': (16, 64)} type_opt = BayesianOptimization(f=type_cv, pbounds=pbounds_type, random_state=42, verbose=2) type_opt.maximize(init_points=6, n_iter=12) best_type = type_opt.max['params'] # -------------------------------------------------- # 13. 重新训练多分模型(去掉 batch_size) # -------------------------------------------------- best_type_pop = best_type.copy() best_type_pop.pop('batch_size', None) final_type_model = build_type_model(**best_type_pop) es_type = EarlyStopping(monitor='val_accuracy', mode='max', patience=20, restore_best_weights=True, verbose=1) lr_type = ReduceLROnPlateau(monitor='val_accuracy', mode='max', factor=0.5, patience=5, min_lr=1e-5) ckpt_type = ModelCheckpoint('best_type_model.keras', monitor='val_accuracy', mode='max', save_best_only=True, verbose=1) final_type_model.fit(X_train_abn, y_type_train, epochs=120, batch_size=int(best_type['batch_size']), verbose=2, validation_split=0.1, callbacks=[es_type, lr_type, ckpt_type]) # -------------------------------------------------- # 14. 级联预测(测试集) # -------------------------------------------------- y_test_prob = final_bin_model.predict(X_test, verbose=0).ravel() abn_mask = y_test_prob > best_th out_df = pd.DataFrame({ 'sample_idx': np.arange(len(X_test)), '异常概率': y_test_prob, '是否异常': abn_mask.astype(int) }) if abn_mask.sum() == 0: print('测试集未检测到异常磨损') else: X_test_abn = X_test[abn_mask] type_pred_prob = final_type_model.predict(X_test_abn, verbose=0) type_pred = np.argmax(type_pred_prob, axis=1) + 1 # 回到 1–5 out_df.loc[abn_mask, '预测磨损型'] = type_pred print('\n异常型预测分布:', out_df['预测磨损型'].value_counts().sort_index()) # 保存结果 out_df.to_excel('测试集_级联预测结果.xlsx', index=False) print('\n结果已保存 → 测试集_级联预测结果.xlsx')C:\Users\Lenovo\PycharmProjects\pythonProject1\.venv\Scripts\python.exe C:\Users\Lenovo\PycharmProjects\pythonProject1\异常磨损.py | iter | target | lstm1 | lstm2 | lstm3 | dropout | lr | batch_... | gamma | alpha | ------------------------------------------------------------------------------------------------------------------------- 2025-09-23 22:25:54.170990: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations. To enable the following instructions: SSE3 SSE4.1 SSE4.2 AVX AVX2 FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags. | 1 | 1.0 | 135.91170 | 123.26857 | 74.559515 | 0.3394633 | 0.0008644 | 23.487736 | 1.5871254 | 0.9165440 | | 2 | 0.9838709 | 179.41408 | 99.974967 | 17.646759 | 0.4879639 | 0.0041789 | 26.192277 | 1.7727374 | 0.7458511 | | 3 | 0.9946236 | 122.41451 | 82.376617 | 50.555601 | 0.2164916 | 0.0030980 | 22.695705 | 1.9382169 | 0.7915904 | | 4 | 1.0 | 151.56543 | 107.37689 | 31.973902 | 0.3056937 | 0.0030028 | 18.229619 | 2.4113172 | 0.7426310 | | 5 | 1.0 | 76.489905 | 123.09301 | 93.250562 | 0.4233589 | 0.0015926 | 20.688261 | 2.5263495 | 0.8100381 | | 6 | 1.0 | 87.431341 | 79.536983 | 18.751081 | 0.4637281 | 0.0013680 | 47.801069 | 1.9675666 | 0.8300170 | | 7 | 0.9838709 | 151.64387 | 108.05156 | 33.210093 | 0.3047760 | 0.0019968 | 17.370767 | 2.2596136 | 0.7493951 | | 8 | 1.0 | 207.63514 | 52.826583 | 25.072802 | 0.3162133 | 0.0018876 | 61.947854 | 2.7411665 | 0.9293844 | | 9 | 1.0 | 116.10946 | 57.215411 | 33.765850 | 0.1049776 | 0.0007837 | 63.286934 | 1.8170114 | 0.7413915 | | 10 | 1.0 | 80.761740 | 61.367136 | 32.208205 | 0.3440713 | 0.0023078 | 36.162482 | 1.6843879 | 0.7710770 | | 11 | 1.0 | 153.20095 | 66.419383 | 95.684081 | 0.4571187 | 0.0022739 | 57.864851 | 1.8958393 | 0.8710439 | | 12 | 1.0 | 87.445312 | 121.16384 | 25.812336 | 0.3630193 | 0.0040144 | 31.316988 | 2.3228903 | 0.8363443 | | 13 | 1.0 | 73.709315 | 119.30836 | 38.733579 | 0.1933675 | 0.0045279 | 29.510451 | 2.1319602 | 0.8940009 | | 14 | 1.0 | 182.27697 | 45.327479 | 19.691559 | 0.1714069 | 0.0027865 | 25.721406 | 2.1917102 | 0.8625757 | | 15 | 1.0 | 152.19878 | 42.491115 | 63.709088 | 0.1071735 | 0.0038790 | 40.120381 | 2.7839652 | 0.7519634 | | 16 | 1.0 | 197.40245 | 43.079261 | 38.372960 | 0.3732381 | 0.0037628 | 57.029413 | 2.7235014 | 0.7404201 | | 17 | 1.0 | 176.97395 | 61.954725 | 68.060175 | 0.3824341 | 0.0015251 | 36.412878 | 2.7052709 | 0.8370069 | | 18 | 0.9892473 | 215.98821 | 126.71244 | 36.321956 | 0.1183744 | 0.0018048 | 61.276768 | 2.8230706 | 0.7190355 | ========================================================================================================================= Epoch 1/120 Traceback (most recent call last): File "C:\Users\Lenovo\PycharmProjects\pythonProject1\异常磨损.py", line 127, in <module> final_bin_model.fit(X_tr, y_tr, epochs=120, batch_size=int(best_bin['batch_size']), verbose=2, File "C:\Users\Lenovo\PycharmProjects\pythonProject1\.venv\Lib\site-packages\keras\src\utils\traceback_utils.py", line 122, in error_handler raise e.with_traceback(filtered_tb) from None File "C:\Users\Lenovo\PycharmProjects\pythonProject1\异常磨损.py", line 70, in focal_loss_fixed return -tf.reduce_mean(alpha_t * tf.pow(1 - p_t, gamma) * tf.math.log(p_t)) ~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~ TypeError: Input 'y' of 'Mul' Op has type float32 that does not match type float64 of argument 'x'. 进程已结束,退出代码为 1
09-24
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值