JS应用

原生JS文件上传

JS实现文件上传

<!-- 表单用于文件上传,指定了上传的目标地址为 "upload.php",使用 POST 方法提交,并设置 enctype 为 "multipart/form-data" -->
<form action="upload.php" method="POST" enctype="multipart/form-data">
<!-- 为文件上传输入框添加标签 -->
<label for="file">选择文件:</label>
<br>
<!-- 这是一个包含文件上传输入框的 HTML 代码,并且在用户选择文件时触发 CheckFileExt 函数 -->
<input type="file" id="file" name="f" onchange="CheckFileExt(this.value)">//改变时,触发cheakfileext函数
<br>
<!-- 提交按钮 -->
<button type="submit">上传文件</button>
</form>
<script>
// JavaScript 函数 CheckFileExt 用于检查文件后缀名
function CheckFileExt(filename){
var flag = false;//flag为一个标志
// 允许的文件后缀名数组
var exts = ['png', 'gif', 'jpg'];
// 获取文件名中最后一个点后面的部分,即文件的后缀名
var index = filename.lastIndexOf('.');
var ext = filename.substr(index + 1);

// 遍历允许的文件后缀名数组
for (var i = 0; i < exts.length; i++) {
// 检查是否匹配允许的后缀名
if (ext === exts[i]) {
// 文件后缀名正确,设置 flag 为 true,显示提示信息,并跳出循环
flag = true;
alert('文件后缀名正确');
break;
}
}

// 如果 flag 为 false,表示文件后缀名错误,显示错误提示,并强制刷新页面
if (!flag) {
alert('文件后缀错误!')
location.reload(true);//重载页面,错误的话重新刷新页面
}
}
</script>

直接写在html代码中,前端JS验证

安全问题

禁用JS或删除过滤代码绕过

删除过滤代码:

将页面源代码复制下来,在本地创建,并删除检验代码的函数调用onchange=”CheckFileExt(this.value)”

将调用的文件上传地址,切换为使用网址路由的样式http://192.168.137.1:84/js/upload.php

成功绕过文件检验,上传成功1.exe

在本地源代码文件中实现远程文件上传,使用调用的文件上传地址

JS导入库开发

后端php实现账户判断,前端JS实现登录处理

val() 是 jQuery 的一个方法,用来获取或设置表单元素的值

JS实现登录验证

$.ajax()是一个用于执行异步HTTP请求的jQuery函数。它允许您通过JavaScript代码向服务器发送请求,并在不刷新整个页面的情况下接收和处理响应。

下面是一个基本的$.ajax()用法示例:

$.ajax({
url: "example.com/data", // 请求的URL
method: "GET", // HTTP请求方法(GET、POST等)
data: { // 发送到服务器的数据(可选)
param1: "value1",
param2: "value2"
},
success: function(response) { // 请求成功时的回调函数
console.log("请求成功!");
console.log(response); // 服务器响应的数据
},
error: function(xhr, status, error) { // 请求失败时的回调函数
console.log("请求失败!");
console.log(error); // 错误信息
}
});
<div class="login">
<!-- 登录标题 -->
<h2>后台登录</h2>
<!-- 用户名标签和输入框 -->
<label for="username">用户名:</label>
<input type="text" name="username" id="username" class="user">
<!-- 密码标签和输入框 -->
<label for="password">密码:</label>
<input type="password" name="password" id="password" class="pass">
<!-- 登录按钮 -->
<button>登录</button>
</div>

**<!-- 引入 jQuery 库 -->
<script src="js/jquery-1.12.4.js"></script>**

<!-- JavaScript 代码 -->
<script>
// 当按钮被点击时执行以下函数
$("button").click(function (){
// 使用 AJAX 发送 POST 请求到 'logincheck.php'
$.ajax({
type: 'POST',
url: 'logincheck.php',//数据提交地址
// 发送的数据包括用户名和密码
data: {
myuser: $('.user').val(),
mypass: $('.pass').val()
},
// 请求成功时执行的函数
success: function (res){
console.log(res);
// 如果返回的信息代码为1,表示登录成功,弹出提示并执行相应的处理
if(res['infoCode'] == 1){
alert('登录成功');
// 登录成功处理事件(注释部分为示例,可根据需要进行处理)
// location.href='index.php';
} else {
// 如果信息代码不为1,表示登录失败,弹出失败提示
alert('登录失败');
}
},
// 指定返回的数据类型为 JSON
dataType: 'json',
});
});
</script>
<?php
// 从 POST 请求中获取用户提交的用户名和密码
$user = $_POST['myuser'];
$pass = $_POST['mypass'];

// 真实情况下,应该在数据库中进行验证获取用户信息

// 假设用户名是 'xiaodi',密码是 '123456'
**//$success 是一个关联数组变量,通过使用 'msg' 作为键,将 'ok' 作为值存储在其中。
$success = array('msg' => 'ok');**

// 检查用户名和密码是否匹配
if ($user == 'xiaodi' && $pass == '123456') {
// 如果匹配,设置信息代码为1表示登录成功,并进行相应的处理
$success['infoCode'] = 1;
} else {
// 如果不匹配,设置信息代码为0表示登录失败
$success['infoCode'] = 0;
}

**// 将结果以 JSON 格式输出
//必须要回调输出,不然前端无法获取infocode的值
echo json_encode($success);**

安全问题

登陆成功后的处理操作写在JS里

if(res['infoCode'] == 1){
alert('登录成功');
// 登录成功处理事件(注释部分为示例,可根据需要进行处理)
// location.href='index.php';
}

我们直接抓包修改infoCode的值为1,可以绕过登录

前提是仅仅通过infoCode这一参数来校验是否登录成功

当成功后的操作如跳转到其他页面写在PHP中,相对安全

前端js只起到判断作用,无法执行跳转等逻辑

逻辑购买

<!DOCTYPE html>
<html lang="en">
<head>
<!-- 设置文档的字符集为UTF-8 -->
<meta charset="UTF-8">
<!-- 设置页面标题 -->
<title>商品购买</title>
</head>
<body>
<!-- 商品图片 -->
<img src="iphone.jpg" width="300" height="300" alt=""><br>
<!-- 当前拥有的金钱 -->
金钱:10000<br>
<!-- 商品价格 -->
商品价格:8888<br>
<!-- 输入购买数量的文本框 -->
数量:<input type="text" name="number" class="number">
<!-- 购买按钮 -->
<button>购买</button>
</body>
</html>

<!-- 引入 jQuery 库 -->
<script src="js/jquery-1.12.4.js"></script>
<!-- JavaScript 代码 -->
<script>
// 当购买按钮被点击时执行以下函数
$("button").click(function (){
// 使用 AJAX 发送 POST 请求到 'shop.php'
**$.ajax({
type: 'POST',
url: 'shop.php',
// 发送的数据,包括购买数量
data: {
num: $('.number').val(),
},
// 请求成功时执行的函数
success: function (res){
// 在控制台输出返回的数据
console.log(res);
// 如果返回的信息代码为1,表示购买成功
if(res['infoCode'] == 1){
// 弹出成功提示
alert('购买成功');
// 购买成功的流程(你可以在这里添加额外的处理)
} else {
// 如果信息代码不为1,表示购买失败
// 弹出失败提示
alert('购买失败');
}
},
// 指定返回的数据类型为 JSON
dataType: 'json',
});**
});
</script>

<?php
// 从 POST 请求中获取购买数量
$num = $_POST['num'];

// 假设购物车中已有的金钱数为10000,商品价格为8888
// 真实情况下,应该在数据库中获取用户的金钱数等信息

// 初始化一个关联数组变量,通过使用 'msg' 作为键,将 'ok' 作为值存储在其中。
$success = array('msg' => 'ok');

**// 检查购买是否合法(金钱是否足够支付)
if (10000 >= ($num * 8888)) {
// 如果购买合法,设置信息代码为1表示购买成功
$success['infoCode'] = 1;
} else {
// 如果购买不合法,设置信息代码为0表示购买失败
$success['infoCode'] = 0;
}

// 将结果以 JSON 格式输出
echo json_encode($success);**
?>

将抓到的包,设置其返回包也抓取,并将访问失败返回包的改为1发送,后购买成功。

当成功后的操作如购买成功后的逻辑到其他页面写在js中,不安全

DOM树

DOM:文档操作对象

浏览器提供的一套专门用来操作网页代码内容的功能,实现自主或用户交互动作反馈

演示操作:

当点击按钮的时候会进行图片替换,要获取该图片的对象,获取对象的src属性,替换src属性

获取对象

获取对象三种方法

1.标签:直接写

2.Class:加上符号.

i3.id:加上符号#

<!-- 这是标题 -->
<h1 id="myHeader" onclick="getValue()">这是标题</h1>

<!-- 选择第一个 h1 元素 -->
document.querySelector('h1')

<!-- 选择所有具有 'id' 类的元素 -->
document.querySelector('.id')

<!-- 选择具有 'myHeader' id 的元素 -->
document.querySelector('#myHeader')

console.log(): 是一个用于在控制台输出信息的方法。它是由浏览器或其他 JavaScript 运行环境提供的调试工具。通过调用 console.log(),您可以在控制台中输出消息、变量的值、调试信息等,以便在开发过程中进行调试和测试。

例如:
console.log("Hello, world!");
这行代码将在控制台输出字符串 "Hello, world!"

获取对象属性

<img src="1.jpg" width="300" height="300" >
<button onclick="update()">刷新</button>
<!--当点击按钮,执行update函数-->
<script>
function update(){
const s=document.querySelector('img')//获取img标签的内容,并赋值给s(这里也可以使用var声明变量s)
console.log(s)//控制台打印s变量的内容
}

</script>

每次点击刷新按钮,控制台都会输入img标签的内容

操作元素数据

innerText 不解析后续代码

<h1 onclick="update1()">这是标题</h1>
<img src="1.jpg" width="300" height="300" >
<button onclick="update()">刷新</button>
<!--当点击按钮,执行update函数-->
<script>
function update(){
const s=document.querySelector('img')//获取img标签的内容,并赋值给s(这里也可以使用var声明变量s)
console.log(s)//控制台打印s变量的内容
}
function update1(){
const s=document.querySelector('h1')//获取h1标签的内容,并赋值给s
console.log(s.innerText)//控制台打印h1标签的数据
}

</script>

每次点击“这是标题”,控制台都会打印一遍

当吧update1中获得的h1标签的数据先赋值给一个变量,在更改这个变量的内容,最后打印数据,h1标签的数据就会被改变

function update1(){
const s=document.querySelector('h1')
const str=s.innerText="这是hx"
console.log(str)
}

innerHTML 解析后续代码

<h1 onclick="update1()">这是标题</h1>
<img src="1.jpg" width="300" height="300" >
<button onclick="update()">刷新</button>
<!--当点击按钮,执行update函数-->
<script>
function update(){
const s=document.querySelector('img')//获取img标签的内容,并赋值给s(这里也可以使用var声明变量s)
console.log(s)//控制台打印s变量的内容
}
function update1(){
const s=document.querySelector('h1')//获取img标签的内容,并赋值给s(这里也可以使用var声明变量s)
const str=s.innerText="这是hx<br>"//!!!!!!!!!!!!
console.log(str)
}

</script>

当我们使用innerText,后面的html标签不会被解析

使用innerHTML

<h1 onclick="update1()">这是标题</h1>
<img src="1.jpg" width="300" height="300" >
<button onclick="update()">刷新</button>
<!--当点击按钮,执行update函数-->
<script>
function update(){
const s=document.querySelector('img')//获取img标签的内容,并赋值给s(这里也可以使用var声明变量s)
console.log(s)//控制台打印s变量的内容
}
function update1(){
const s=document.querySelector('h1')//获取img标签的内容,并赋值给s(这里也可以使用var声明变量s)
s.innerHTML="这是hx<Hr>"
console.log(s.innerHTML)
}

</script>

当点击标题,


标签被执行,页面更改

操作元素属性

实现点击按钮更换图片

<h1 onclick="update1()">这是标题</h1>
<img src="1.jpg" width="300" height="300" >
<button onclick="update()">刷新</button>
<!--当点击按钮,执行update函数-->
<script>
function update(){
const s=document.querySelector('img')//获取img标签的内容,并赋值给s(这里也可以使用var声明变量s)
s.src='2.png'
console.log(s.src)
}
</script>

当我们点击刷新,图片被更新为2.png

安全问题

本身的前端代码通过DOM技术实现代码的更新修改,但是更新修改如果修改的数据可以由用户来指定,就会造成DOM-XSS攻击

在用户可控输入的地方构造xss语句

闭合标签

网易云翻译:可以使用带外dns,造成数据库ip泄露

正向翻译有过滤,当鼠标放在右边被翻译的文字,正向没有翻译出来再次尝试翻译,反向翻译没有过滤,执行构造的,被解析,成功带外查询

典型的DOM-XSS

编码加密&逆向调试

编码加密

通过js导入库来实现对数据的md5、AES、SHA1等加密

没有实现..存在遗留问题

逆向调试

首先找到相应的源码内容位置

找到表单的name属性的值

CTRL+SHIFT+F在调试器中全局搜索name的值,找相应的加密函数

Login.js

审计代码,找到相应的加密函数

找到加密逻辑

根据相应的加密函数,将payload加密,构成有效payload

如果加密格式不显示出来,怎样判断加密的方式是什么?

可以借助检查的控制台,尝试输入获取加密后的密码值,再和提交表单的加密值进行比对,若一致则证明识别出。(一般安全防护比较强的,不会把运行的所以东西全加载到浏览器上)

断点调试

当我们找到了相应的加密函数

logindata.UserName = encodeURI(encrypt.encrypt(numMobile));
logindata.Mobile = encodeURI(encrypt.encrypt(numMobile));;
//加密密码
logindata.Password = encodeURI(encrypt.encrypt(numPassword));

采用之前的方式在控制台中输入相应的代码encodeURI(encrypt.encrypt(numPassword)),报错encrypt is not defined,原因是:有一些文件只在服务器本地执行,不会加载到浏览器中

必须采用调试断点的方式来,通过服务器获取其执行文件,然后修改对应的返回密文即可

对应地方(加密函数那一行代码)打上断点,点击登录,进入断点调试,发现右侧出现输入的账号密码内容

再次打开控制台,并输入encodeURI(encrypt.encrypt(numPassword))发现成功回显加密后的密码

我们在控制台构造payload并用加密函数进行加密,将加密后的有效payload提交,进行测试

NodeJS

NodeJS教程

NodeJS是运行在服务器的JS,与传统JS不同(传统JS运行在前端浏览器,通过查看源代码可以看到完整JS代码),而NodeJS运行结果,查看源代码只能查看运行结果

访问之后当我们查看源代码,只有输出结果hello world

实现用户登录

前端登录页面

<div class="login">
<!-- 登录标题 -->
<h2>后台登录</h2>
<!-- 用户名标签和输入框 -->
<form action="http://127.0.0.1:3001/login" method="post">
<label for="username">用户名:</label>
<input type="text" name="username" id="username" class="user">
<!-- 密码标签和输入框 -->
<label for="password">密码:</label>
<input type="password" name="password" id="password" class="pass">
<!-- 登录按钮 -->
<button>登录</button>
</div>
// 引入 Express 框架
const express = require('express');
const bodyParser = require('body-parser');

// 创建 Express 应用程序实例
const app = express();
创建一个用于解析 URL 编码的 bodyParser 中间件实例
const urlencodedParser = bodyParser.urlencoded({ extended: false });

// 处理 '/login' 路径的 GET 请求,返回简单的登录页面
app.get('/login', function(req, res) {//req表示接收请求,res 返回响应
// 从请求中获取用户名和密码
const u = req.query.username;//query 从url中获取内容
const p = req.query.password;**

console.log(u);
console.log(p);

// 检查用户名和密码是否为 admin 和 123456
if (u === 'admin' && p === '123456') {
res.send('欢迎进入后台管理页面');
} else {
res.send('登录用户或密码错误');
}
});

// 处理 '/login' 路径的 POST 请求,使用 bodyParser 解析表单数据
app.post('/login', urlencodedParser, function(req, res) {
// 从请求中获取表单提交的用户名和密码
const u = req.body.username;
const p = req.body.password;**

console.log(u);
console.log(p);

// 检查用户名和密码是否为 admin 和 123456
if (u === 'admin' && p === '123456') {
res.send('欢迎进入后台管理页面');
} else {
res.send('登录用户或密码错误');
}
});

// 处理根路径的 GET 请求,发送名为 'sql.html' 的文件
app.get('/', function(req, res) {
res.sendFile(__dirname + '/' + 'sql.html');
});

// 启动服务器,监听端口 3001
const server = app.listen(3001, function() {
console.log('Web 服务器已经启动,监听端口 3001!');
});

req.query 用于处理 URL 查询字符串参数(GET请求),而 req.body 用于处理 (POST 请求)中的表单数据

POST请求

还需要下载const bodyParser = require(‘body-parser’); 相关库 npm i body-parser

并且post请求还需要创建一个解析URL编码的bodyParser (中间件实例)

sql.js里同时写了get和post处理逻辑,当sql.html里方法属性为get时则使用get处理逻辑

<form action="http://127.0.0.1:3001/login" method="post">

成功登录

连接数据库

导入mysql ,npm i mysql下载相关依赖

const mysql = require('mysql');

导入 mysql 模块

var connection = mysql.createConnection({//连接数据库信息
host : 'localhost',
user : 'root',
password : 'root',
database : 'dome01'
});

文件操作

导入fs

const fs=require('fs');//导入fs库

fs.readdir('./',function(error,files){
console.log(files);//输出当前目录下的文件
})

启用服务器

// 引入文件系统和 Express 框架
const fs = require('fs');
const express = require('express');
const app = express();

// 处理 '/file' 路径的 GET 请求
app.get('/file', function (req, res) {
// 从请求中获取目录参数
const dir = req.query.dir;
console.log(dir);

// 调用文件管理函数,传递目录参数
filemanage(dir);
});

// 启动 Express 应用监听在3000端口
var server = app.listen(3000, function () {
console.log('Web应用已启动在3000端口!');
});

// 文件管理函数,接收一个目录参数
function filemanage(dir) {
// 使用 fs.readdir 读取目录下的文件
fs.readdir(dir, function (error, files) {
// 打印目录中的文件列表
console.log(files);
});
}

传参

命令执行

const rce=require('child_process')

//node.js 调用系统命令执行 calc计算器
// rce.exec('calc');
//rce.spawnSync('calc')

//node.js 调用代码执行
// eval(console.log(1))

//代码执行调用命令执行 把字符串当作代码解析
eval("require('child_process').exec('calc')")

exec & spawnSync 调用系统命令

eval调用代码命令执行,将字符串当做代码解析

安全问题

SQL注入、文件操作、RCE、

实战测试NodeJS安全:

判断:参考前期的信息收集

黑盒:通过对各种功能和参数进行payload测试

白盒:通过对代码中写法安全进行审计分析

原型链污染

如果攻击者控制并修改了一个对象的原型,(proto)

那么将可以影响所有和这个对象来自同一个类、父祖类的对象。

// foo是一个简单的JavaScript对象
let foo = {bar: 1} //1=1 0 __proto__= x
// 原型链污染
// foo.bar 此时为1
console.log(foo.bar)//输出为1

// 修改foo的原型(即Object)
foo.__proto__.bar = '2'

// // 由于查找顺序的原因,foo.bar仍然是1
console.log(foo.bar)//输出为1

// // 此时再用Object创建一个空的zoo对象
let zoo = {}

// 查看zoo.bar,此时bar为2
console.log(zoo.bar)//输出为2

我们并没有对zoo赋值,但zoo.bar输出为2,是因为继承了foo.bar父类的赋值2

利用原型链污染调用计算器

// 创建一个包含属性 bar 的对象 foo,并将 bar 设置为 1
let foo = {bar: 1};

// 输出 foo 对象的 bar 属性,预期输出为 1
console.log(foo.bar); // 输出: 1

// 修改 foo 对象的原型链上的 bar 属性,将其设置为执行命令 'require(\'child_process\').execSync(\'calc\');'
//调用计算机
foo.__proto__.bar = 'require(\'child_process\').execSync(\'calc\');';

// 输出 foo 对象的 bar 属性,预期输出仍为 1,因为直接属性优先于原型链上的属性
console.log(foo.bar); // 输出: 1

// 创建一个空对象 zoo
let zoo = {};

// 使用 eval 执行 zoo 对象的 bar 属性,由于 zoo 对象没有 bar 属性,会导致 ReferenceError
//调用计算机
console.log(eval(zoo.bar));

yapi漏洞

yapi token注入漏洞-CSDN博客

webpack

为什么使用webpack

function test(){
console.log('test');
}
test()
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="src/2.js"></script>
<script src="src/1.js"></script>
</body>
</html>

由于函数要先声明再调用,所以要先引用1.js,在引用2.js

如果我们先写2再写1会产生报错,而在正常的业务中可能会有很多js文件,按顺序处理过于麻烦

Webpack是一个模块打包器。在Webpack中会将前端的所有资源文件都作为模块处理。它将根据模块的依赖关系进行分析,生成对应的资源

使用

1.先创建js文件

export default function count(x,y){
//export default是一种模块导出方式,主要用于模块化开发。它允许你将模块中的某个部分(比如函数、变量或类)标记为默认导出,便于其他模块导入和使用
return x-y;
}
export default function sum(x,y){
return x+y;
}
import count from "./count.js";//webpack语法,不是js语法
import sum from "./sum.js";

console.log(sum(1,2));
console.log(count(1,2));
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="main.js"></script>
</body>
</html>

2.创建webpack配置文件 webpack.config.js(名称不能修改)

// 引入path模块,用于处理文件路径
const path = require('path');

// Webpack配置对象
module.exports = {
// 指定入口文件,即Webpack从这个文件开始构建依赖图
entry: './src/main.js',

// 指定输出配置
output: {
// 输出的文件路径,使用path.resolve确保路径的正确性
path: path.resolve(__dirname, 'dist'),

// 输出的文件名
filename: 'bundle.js',

// 在每次构建前清理输出目录
clean: true,
},

// 指定打包模式,可以是 'development' 或 'production'
mode: "development", // 或者 "production"
//mode:"production",
};

entry: 指定入口文件,即Webpack从哪个文件开始构建依赖关系图。

output: 指定输出的目录和文件名,以及是否在每次构建前清理输出目录。

mode: 指定打包的模式,可以是 ‘development’ 或 ‘production’。

development 模式下会启用一些开发工具,容易造成源码泄露

production 模式下会进行代码优化,代码极简化。

3.运行webpack打包命令:npx webpack

4.打包成功后,我们将html里的代码换成打包后的包文件

5.启用调试html文件,控制台成功输出结果

源代码中可以看到打包的文件已经源文件

安全问题

WebPack源码泄漏-模式选择

development 模式下会启用一些开发工具,容易造成源码泄露

production 模式下会进行代码优化,代码极简化。

当我们在打包的时候选择(webpack.config.js文件配置)development模式,会将源码文件泄露,前端可以直接看到文件内容

development

production

JQuery

jQuery是一个快速、简洁的JavaScript框架,是一个丰富的JavaScript代码库。设计目的是为了写更少的代码,做更多的事情。它封装JavaScript常用功能代码,提供一种简便的JavaScript设计模式,优化HTML文档操作、事件处理、动画设计和Ajax交互

Javascript框架库漏洞验证-CSDN博客