彻底理解前端安全面试题(1)—— XSS 攻击,3种XSS攻击详解,建议收藏(含源码)
前言
前端关于网络安全看似高深莫测,其实来来回回就那么点东西,我总结一下就是 3 + 1 = 4,3个用字母描述的【分别是 XSS、CSRF、CORS】 + 一个中间人攻击。当然 CORS 同源策略是为了防止攻击的安全策略,其他的都是网络攻击。除了这 4 个前端相关的面试题,其他的都是一些不常用的小喽啰。
我将会在我的《面试题一网打尽》专栏中先逐一详细介绍,然后再来一篇文章总结,预计一共5篇文章,欢迎大家关注~
本篇文章是前端网络安全相关的第一篇文章,内容就是 XSS 攻击。
一、准备工作
跨站脚本攻击(cross-site scripting),为了和 css 区分所有才叫 XSS【也叫作代码注入攻击】,重点在【脚本】两个字,所以同样都是利用 script 标签,XSS 和后面说的 CSRF 还是有区别的。通过在网站注入恶意脚本,使脚本在用户的浏览器上运行,从而盗取用户的信息或者破环页面的结构。
1.1 拉取仓库
很多知识都需要结合实际的代码来学习,所以本篇文章的基础是需要一个服务端的项目,可以跟着我的这篇文章搭建自己的服务端项目。或者直接克隆我的仓库代码在这个提交上拉一个新分支,本篇文章所有的代码都是在这个提交基础上进行的。
1.2 新增 xss 文件夹
在项目的根目录增加一个 xss 文件夹,并且在 xss 下面新建 index.html 和 index.js
__dirname
是 Node.js 中的一个特殊变量,表示当前执行脚本所在的目录的绝对路径。它是全局对象global
的属性之一,可在任何地方使用。具体可以看这个
至于运行的时候为什么加上目录参数,请看这篇文章 。
1.3 提交代码
二、攻击方式
顾名思义,xss 的攻击方式重点是脚本,就是利用 js 脚本干的一些坏事,主要的攻击方式如下:
- 利用脚本获取页面的数据,盗用 cookie、localStorage 等
- 破坏页面结构,操作 dom
- DOS 攻击,拒绝服务请求,恶意发送请求,占用服务器资源
反正 js 能干的事情都可以利用。
三、攻击类型
xss 的攻击类型分别是 存储型、反射型、DOM 型,下面开始做详细的讲解
3.1 存储型 XSS 攻击
恶意脚本由前端生成、发送并存在目标服务器上,属于服务器端漏洞,重点是:
- 这个脚本是前端某个用户写的,好好想想,肯定是这样的,服务端不会无缘无故的多出来数据;
- 服务器在接收到前端传的内容后,没有经过检查就存到数据库中
- 攻击发生在前端再一次访问存储的数据的时候
3.1.1 具体流程
- 一个用户修改一个公共【文件名】为一段脚本,如
<img src='invalid-image' onerror='alert("我是秦始皇,加v给我100万")'>
- 服务器对【文件名】没有过滤(对不合法的文件名没有进行转义等处理),就保存在服务端数据库了
- 当其他用户访问这个公共【文件名】的时候就会触发攻击
- 脚本中可以获取网站的 cookie,把 cookie 数据传到黑客服务器【或者是利用脚本破坏页面结构等】
- 拿到用户 cookie 信息后,就可以利用 cookie 信息在其他机器上登录改用户的账号,并利用用户账号进行一些恶意操作
3.1.2 代码模拟
我模拟的是【破坏页面结构】的 XSS 攻击,我们再在 XSS 文件夹下新建两个文件
- data.txt 用来存数据来模拟数据库
- index2.html 用来展示第二个页面,用于访问数据库中的数据
现在我们总共有四个文件了。
系统功能描述:
- 一个公开可访问的书籍列表,一个管理员用户 1 可以在页面 1 (index.html) 修改书籍的名称;
- 一个普通用户 2, 可以在页面 2(index2.html)访问书籍列表(也就是书籍名)
(1)index.html 的代码
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=`, initial-scale=1.0" /><title>Document</title><style>h1,h2 {margin: 0;}.box {display: inline-flex;flex-direction: column;}.book-name {margin: 10px 0;width: 400px;height:100px}.button {width: 100px;height: 38px;}</style></head><body><div class="box"><h1>【首页,用户1】</h1><h1>设置一个公开的书籍的名称</h1><div>这个书籍是所用用户都可以访问的</div><div>修改书名:</div><textarea class="book-name" id="name" ></textarea><button class="button" onclick="saveName()">保存</button></div><script>function saveName() {const name = document.getElementById('name').value;if (name) {fetch('saveName', {method: 'post',headers: {'content-type': 'application/json'},body: JSON.stringify({name: name}),}).then(() => {console.log('保存成功 姓名:', name)})}}</script></body>
</html>
(2)index2.html 的代码
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8" /><meta name="viewport" content="width=`, initial-scale=1.0" /><title>Document</title><style>h1,h2 {margin: 0;}.box {display: inline-flex;flex-direction: column;}.book-name {margin: 10px 0;width: 400px;height: 100px;}.button {width: 100px;height: 38px;}</style></head><body><div class="box"><h1>【另一个页面,用户2】</h1><h1>书籍列表页面</h1><div>访问公开的书籍</div><div>书名</div><div id="name"></div></div><script>// 初始化的时候就获取数据fetch('/getName').then((res) => {return res.json();}).then((data) => {const name = data.name;const ele = document.getElementById('name');// 设置书名ele.innerHTML = name;});</script></body>
</html>
(3)index.js 的代码
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser')
const fs = require('fs')const app = express();app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());// 首页 -> 用户1 保存数据
app.get('/', function (req, res) {res.sendFile(path.join(__dirname, '/index.html'));
});// 首页 -> 保存书名
app.post('/saveName', function (req, res) {const { name } = req.bodyfs.writeFileSync(path.resolve(__dirname, 'data.txt'), name)res.send('保存成功');
});// 新建另一个页面
app.get('/index2', function (req, res) {res.sendFile(path.join(__dirname, '/index2.html'));
});
// 另一个页面 -> 用户2 获取数据
app.get('/getName', function (req, res) {// 从 data.txt 中取出存储的书名const name = fs.readFileSync(path.resolve(__dirname, 'data.txt')).toString()console.log(name)res.send(JSON.stringify({name: name,}));
});app.listen(3000);
注意 xss/index.js 中关于使用 express 写服务端代码,有两个知识点
(1)post 请求需要使用 body-parser 解析 body 的 json 数据
(2)写入/读取 data.txt 是用node 的核心模块 fs,方法 fs.writeFileSync / s.readFileSync
(3)fs.readFileSync 的结果是 buffer 需要转成字符串 toString()
data.txt 里面不必输入任何内容,我们会通过代码进行写入。
(4)运行代码
npm run dev xss
访问 localhost:3000,输入一段恶意的代码作为书名,点击保存
点击保存之后,输入的内容会保存在 data.txt 中
再打开 localhost:3000/index2.html,这样一个存储型的、对于 dom 结构的破环的 XSS 攻击就完成了。
这里面有一个知识点就是我们在 index.html 中保存的恶意脚本是
<img src='invalid-image' onerror='alert("我是秦始皇,加v给我100万")'>
我们用了一个 img 标签,然后使用 onerror 事件里面写一些脚本,而没有这么写,为啥呢?
<script>alert(1)</script>
这是因为我们在 index2.html 里面使用 innerHTML 将数据渲染在页面上,使用 innerHTML 直接渲染 script 字符串,脚本是不会被执行的。 而事件处理器,如 img 的 onerror 事件却可以触发。
(5)提交代码
3.2 反射型 XSS 攻击
恶意脚本在前端访问的 URL 中,要用户主动点击 URL,服务器解析 URL, 并返回恶意脚本,属于服务端漏洞,重点是:
- 恶意脚本不是前端用户手动写的,和存储型有区别
- 恶意脚本在 URL 上,需要用户手动点击才能触发攻击
- 服务器收到访问 URL 的请求时,解析 URL 得到恶意脚本,然后返回给客户端
- 服务器不会存储恶意脚本,只会返回(反射)它
3.2.1 具体流程
- 黑客诱导用户访问有恶意代码的 URL ,如 https://danger.com?xss=<script>alert('attack)</script>
- 服务器接收到访问 URL 的请求
- 服务器解析 URL ,得到 XSS 的值,但是并没有对 XSS 的值做校验是否合法,对于不合法的没有进行转义
- 服务器将解析后的结果,反射给浏览器,如返回 { xss : <script>alert('attack)</script> }
- 浏览器的恶意代码的 URL 页面有渲染 XSS 值的逻辑
- 此时浏览器弹出警告框
- 一个反射型 XSS 攻击就完成了
黑客经常会通过 qq群或者邮件等渠道诱导用户去点击这些恶意链接。
看到没?没事别惦记乱七八糟的连接,谨防电信诈骗!
3.2.2 代码模拟
(1)新建 xss/ index3.html
<!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><div>反射型 xss 攻击</div><h1><a href="http://localhost:3000/reflect?xss=<script>alert('哈哈,你上当了')</script>"> 点击收款100万 </a></h1></body>
</html>
(2)修改 index.js
注意看这个服务端代码关于 reflect 方法的 get 请求,他就是简单的把参数上的获取并返回,浏览器就能运行这段代码。
(3)运行代码
npm run dev xss
访问 localhost:3000/index3
跳转之后发生了攻击
(4)提交代码
3.3 DOM 型 XSS 攻击
攻击者通过操纵 DOM 来触发攻击,是前端漏洞,不牵扯到服务器。重点是:
- 整个过程服务器不参与
- 脚本的具体来源还是利用网页中用户交互的部分, URL 参数、表单输入、cookie 等
- 多发生在使用 innerHTML 的场景
3.3.1 具体流程
- 从 URL 中取出恶意代码/或者从用户输入的表单/ cookie 中
- 把恶意代码使用 innerHTML 插入页面,改变 dom 结构
尤其是在使用 innerHTML 的时候会出现这种问题,可以使用插件如 xss-filters 避免这一类问题,这个插件的原理是将某些字符进行转义,将 < 转成 < 等
3.3.2 代码模拟
(1)新增 index4.html
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=<device-width>, initial-scale=1.0"><title>Document</title><style>textarea {width: 400px;height: 50px;}</style>
</head>
<body><h1>dom 型 xss 攻击</h1><div>输入</div><textarea id="input"></textarea><button onclick="save()">保存</button><hr><div>输出</div><div id="output"></div><script>function save() {const text = document.getElementById('input').valueif (text) {const output = document.getElementById('output')output.innerHTML = text}}</script>
</body>
</html>
(2)修改 xss/index.js
(3)运行代码
npm run dev xss
点击保存按钮之后,就出现攻击了。
注意,这全程没有服务端的参与,但是我们还是修改 index.js 。但是其实 index.js 里面的代码就是为了起一个服务运行 index4.html 而已, 应该很好理解吧。
(4)提交代码
好了至此三种类型的 XSS 攻击我们都用代码的形式实现。一点都不难吧,光说不练假把式,如果只看理论知识,肯定云里雾里,你跟着一起写一遍代码就理解了,不用背诵就记下来了。
3.4 XSS 攻击防御方法
- 不使用服务端渲染,前两种是服务端的安全漏洞,服务器不能信任前端输入的任何东西,服务端要对输入脚本进行过滤或者转码。<script> 标签被转换为 <script> ,注意,https 不能防止安全问题,只会增加攻击难度和成本;
- 对于 dom 型,对要插入的 html 做好充分的转义, npm 包:xss-filters;
- 使用内容安全策略,csp 建立白名单,告诉浏览器可以执行和加载哪些功能 Content-Security-Policy 服务端设置【设置 csp 有两种方式 http 头部、meta 标签】
- x-content-type-options\x-frame-options\x-xss-protentcion 等httip头部设置
- 敏感信息 cookie 设置 httpOnly
总结
xss 攻击的三种类型都用代码模拟了,我的仓库地址如下,欢迎查看
yangjihong2113/learn-express
内容较多,难免疏漏,如有问题,欢迎指正。
这是一系列的文章,关于网络安全的内容还有 CSRF、CORS 和中间人攻击的内容没有总结,持续更新中,欢迎关注。
相关文章:
彻底理解前端安全面试题(1)—— XSS 攻击,3种XSS攻击详解,建议收藏(含源码)
前言 前端关于网络安全看似高深莫测,其实来来回回就那么点东西,我总结一下就是 3 1 4,3个用字母描述的【分别是 XSS、CSRF、CORS】 一个中间人攻击。当然 CORS 同源策略是为了防止攻击的安全策略,其他的都是网络攻击。除了这…...
UE5.1_AI随机漫游
UE5.1_AI随机漫游 目录 UE5.1_AI随机漫游 AI随机漫游方法 方法1:AI角色蓝图直接写方法...
智慧城市新型基础设施建设综合方案:文件全文52页,附下载
关键词:智慧城市建设方案,智慧城市发展的前景和趋势,智慧城市项目方案,智慧城市管理平台,数字化城市,城市数字化转型 一、智慧城市新基建建设背景 1、城市化进程加速:随着城市化进程的加速&am…...
GitHub Copilot 终极详细介绍
编写代码通常是一项乏味且耗时的任务。现代开发人员一直在寻找新的方法来提高编程的生产力、准确性和效率。 像 GitHub Copilot 这样的自动代码生成工具可以使这成为可能。 GitHub Copilot 到底是什么? GitHub Copilot 于 2021 年 10 月推出,是 GitHub 的…...
LeetCode第63题 - 不同路径 II
题目 解答 class Solution {public int uniquePathsWithObstacles(int[][] obstacleGrid) {int m obstacleGrid.length;int n obstacleGrid[0].length;if (obstacleGrid[0][0] 1) {return 0;}if (obstacleGrid[m - 1][n - 1] 1) {return 0;}int[][] dp new int[m][n];dp…...
python+django网上银行业务综合管理系统vue_bvj8b
本课题主要研究如何用信息化技术改善传统网上银行综合管理行业的经营和管理模式,简化网上银行综合管理的难度,根据管理实际业务需求,调研、分析和编写系统需求文档,设计编写符合银行需要的系统说明书,绘制数据库结构模…...
【软件工程】走进瀑布模型:传统软件开发的经典之路
🍎个人博客:个人主页 🏆个人专栏: 软件工程 ⛳️ 功不唐捐,玉汝于成 目录 前言: 正文 主要阶段: 优点: 缺点: 应用范围: 结语 我的其他博客 前言&am…...
两个字符串间的最短路径问题 (100%用例)C卷 (JavaPythonNode.jsC语言C++)
给定两个字符串,分别为字符串A与字符串B。例如A字符串为ABCABBA,B字符串为CBABAC可以得到下图m*n的二维数组,定义原点为(0,0),终点为(m,n),水平与垂直的每一条边距离为1,映射成坐标系如下图 从原点(0,0)到(0,A)为水平边,距离为1,从(0,A)到(A,C)为垂直边,距离为1;假设两…...
通过ADB来实现脚本来控制手机
ADB 简介 adb的全称为Android Debug Bridge,安卓调试桥,可以通过调试命令来控制手机,诸如开机,关机等按键控制;或者启动,关闭应用;异或进行触摸模拟. 通过学习adb,可以实现简单的脚本控制,最大的特点是不需要root,对于普通手机都可以进行,帮助我们完成一些简单的重复性事件,…...
机器学习之K-means聚类
概念 K-means是一种常用的机器学习算法,用于聚类分析。聚类是一种无监督学习方法,它试图将数据集中的样本划分为具有相似特征的组(簇)。K-means算法的目标是将数据集划分为K个簇,其中每个样本属于与其最近的簇中心。 以下是K-means算法的基本步骤: 选择簇的数量(K值)…...
SSH 端口转发:如何将服务绑定到本地 IP 地址
在日常工作中,我们经常需要访问位于远程服务器上的服务,如数据库、Web 应用程序或其他类型的服务器。直接访问这些服务可能会因为安全限制或网络配置而变得复杂或不可能。这时,SSH 端口转发就成了我们的得力助手。在本篇博客中,我…...
回归预测 | MATLAB实ZOA-LSTM基于斑马优化算法优化长短期记忆神经网络的多输入单输出数据回归预测模型 (多指标,多图)
回归预测 | MATLAB实ZOA-LSTM基于斑马优化算法优化长短期记忆神经网络的多输入单输出数据回归预测模型 (多指标,多图) 目录 回归预测 | MATLAB实ZOA-LSTM基于斑马优化算法优化长短期记忆神经网络的多输入单输出数据回归预测模型 (…...
python实现图像的二维傅里叶变换——冈萨雷斯数字图像处理
原理 二维傅里叶变换是一种在图像处理中常用的数学工具,它将图像从空间域(我们通常看到的像素排列)转换到频率域。这种变换揭示了图像的频率成分,有助于进行各种图像分析和处理,如滤波、图像增强、边缘检测等。 在数学…...
We are a team - 华为OD统一考试
OD统一考试 题解: Java / Python / C 题目描述 总共有 n 个人在机房,每个人有一个标号 (1<标号<n) ,他们分成了多个团队,需要你根据收到的 m 条消息判定指定的两个人是否在一个团队中,具体的: 消息构成为 a b …...
NFC物联网智慧校园解决方案
近场通信(Near Field Communication,NFC)又称近距离无线通信,是一种短距离的高频无线通信技术,允许电子设备之间进行非接触式点对点数据传输交换数据。这个技术由免接触式射频识别(RFID)发展而来,并兼容 RFID,主要用于…...
鸿蒙系列--组件介绍之容器组件
一、Badge 描述:给其他组件添加标记 子组件:支持单个子组件 1.创建数字标记 Badge(value: {count: number, position?: BadgePosition, maxCount?: number, style: BadgeStyle}) 2.创建字符串标记 Badge(value: {value: string, position?: Badge…...
perl使用find函数踩坑
前言 写了一个脚本可以同时检查多个仿真log文件,并生成html表格。按照文件修改时间从新到旧排序。但是一直无法使用stat函数获取修改时间。 结论:find函数会改变程序执行的当前目录,find(\&process_files, $dir);函数是在$dir目录下运行…...
Java IDEA JUnit 单元测试
JUnit是一个开源的 Java 单元测试框架,它使得组织和运行测试代码变得非常简单,利用JUnit可以轻松地编写和执行单元测试,并且可以清楚地看到哪些测试成功,哪些失败 JUnit 还提供了生成测试报告的功能,报告不仅包含测试…...
深入理解 c++ 函数模板
函数模板是C中的一种强大特性,它允许程序员编写一个可以处理多种数据类型的函数。通过使用模板,我们可以编写一次函数,然后在多种数据类型上使用它,这大大提高了代码的复用性。 1. 基本概念 函数模板是一种参数化类型的工具&…...
系列十二、Linux中安装Zookeeper
一、Linux中安装Zookeeper 1.1、下载安装包 官网:Index of /dist/zookeeper/zookeeper-3.4.11 我分享的链接: 链接:https://pan.baidu.com/s/14Hugqxcgp89f2hqGWDwoBw?pwdyyds 提取码:yyds 1.2、上传至/opt目录 1.3、解…...
k8s之陈述式资源管理
1.kubectl命令 kubectl version 查看k8s的版本 kubectl api-resources 查看所有api的资源对象的名称 kubectl cluster-info 查看k8s的集群信息 kubectl get cs 查看master节点的状态 kubectl get pod 查看默认命名空间内的pod的信息 kubectl get ns 查看当前集群所有的命…...
7天玩转 Golang 标准库之 http/net
在构建web应用时,我们经常需要处理HTTP请求、做网页抓取或者搭建web服务器等任务,而Go语言在这方面为我们提供了强大的内置工具:net/http标准库,它为我们操作和处理HTTP协议提供了便利。 基础用法 一:处理HTTP请求 首…...
钡铼技术集IO数据采集可编程逻辑控制PLC无线4G环保物联网关
背景 数据采集传输对于环保企业进行分析和决策是十分重要的,而实时数据采集更能提升环保生产的执行力度,从而采取到更加及时高效的措施。因此实时数据采集RTU成为环保企业的必备产品之一。 产品介绍 在推进环保行业物联网升级过程中,环保RTU在…...
STM32CubeMX教程10 RTC 实时时钟 - 周期唤醒、闹钟A/B事件和备份寄存器
目录 1、准备材料 2、实验目标 3、实验流程 3.0、前提知识 3.1、CubeMX相关配置 3.1.1 、时钟树配置 3.1.2、外设参数配置 3.1.3 、外设中断配置 3.2、生成代码 3.2.1、外设初始化函数调用流程 3.2.2、外设中断函数调用流程 3.2.3、添加其他必要代码 4、常用函数 …...
HarmonyOS4.0系统性深入开发08服务卡片架构
服务卡片概述 服务卡片(以下简称“卡片”)是一种界面展示形式,可以将应用的重要信息或操作前置到卡片,以达到服务直达、减少体验层级的目的。卡片常用于嵌入到其他应用(当前卡片使用方只支持系统应用,如桌…...
002文章解读与程序——中国电机工程学报EI\CSCD\北大核心《计及源荷不确定性的综合能源生产单元运行调度与容量配置两阶段随机优化》已提供下载资源
👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆👆下载资源链接Ǵ…...
Typora快捷键设置详细教程
文章目录 一、快捷键设置步骤二、设置快捷键简单案例参考资料 一、快捷键设置步骤 在typora软件中,快捷键的设置步骤主要为: 打开【文件】–>【偏好设置】,找到【通用】–>【打开高级设置】,找到 conf.user.json 文件。 然…...
《异常检测——从经典算法到深度学习》25 基于深度隔离林的异常检测算法
《异常检测——从经典算法到深度学习》 0 概论1 基于隔离森林的异常检测算法 2 基于LOF的异常检测算法3 基于One-Class SVM的异常检测算法4 基于高斯概率密度异常检测算法5 Opprentice——异常检测经典算法最终篇6 基于重构概率的 VAE 异常检测7 基于条件VAE异常检测8 Donut: …...
第7章 1 异常处理
bug的由来及分类 p81 字符串形式表示的数字之间也可以比较大小 import re ageinput(年龄:) if age>18:print(age)列表的append操作每次只能添加一个元素: lst[] lst.append(A) lst.append(B) # lst.append(A,B) 错误python中的异常处理机制 p82 t…...
昇腾910平台安装驱动、固件、CANN toolkit、pytorch
本文使用的昇腾910平台操作系统是openEuler,之前没了解过,不过暂时感觉用起来和centOS差不多。系统架构是ARM,安装包基本都是带aarch64字样,注意和x86_64区别开,别下错了。 安装依赖 cmake 通过yum安装的cmake版本较…...
有哪些好的模板网站/seo优化技巧有哪些
转自:http://blog.csdn.net/zhuzhihai1988/article/details/7843186 1.如果是在打开的文档范围内:查找: Command F替换: OptionCommandFReplace All 是全部替换本文档范围内的字符串Replace 是替换当前字符串Replace & Find…...
wordpress用php哪个版本好/精准拓客软件哪个好
log4j 的配置将log4j 日志文件的具体配置单独介绍, 是因为它的配置方式将直接决定日志的产生方式,存放位置,输出格式等。在/ src 下建立log4j.properties。内容如下:# 这里定义日志配置根logger,其中后面的…...
怎么查网站在哪备案/seo查询seo
时隔两年的修改: 问题分析:安装了python,Pycharm还找不到Python解释器,原因是系统环境变量中没有指出Python.exe的位置。 解决办法:找到你安装的Python.exe所在的位置,将其添加至系统环境变量就好了。怎么添…...
游戏币销售网站建设/互联网精准营销
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼程序:ORG 0000HLJMP MAINORG 000BHLJMP TIMEORG 1000HHOUR1 EQU 10hHOUR2 EQU 12hMIN1 EQU 14hMIN2 EQU 16hSEC1 EQU 18HCOUNT EQU 20HNUM1 EQU 22HNUM2 EQU 24HLL4 EQU 26Hs1 bit P1.0s2 bit P1.1s3 bit P1.2s4 bit P1.3A1 EQU 36…...
罗定城乡建设局网站/石家庄网站建设
2021中山市普通高中排名一览表2021-05-06 13:40:35文/董玉莹高中对于学生的学习是影响很大的,好的高中能提供学生好的学习环境。本文整理了中山高中排名,来看看都有哪些重点高中。高中排名排名学校名称1中山市中山纪念中学2中山市第一中学3中山市华侨中学…...
做图赚钱的网站有哪些/有哪些搜索引擎网站
读书笔记 每日一记:1 Memcached 缓存服务,可以用于存储session; 阿里云系列产品里面有 session 概述: 是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中ÿ…...