什么是AJAX?
AJAX是Asynchronous javascript and xml 的缩写,用javascript以异步的形式操作xml(现在操作的是json).
-
随着谷歌地图的横空,这种
不需要刷新页面
就可以与服务器通讯
的的方式,很快被人们所知。 -
在传统的web模型当中,
客户端向服务器发送一个请求
,服务器就会返回整个页面
。 -
我们前面学习的
form表单
来传输数据的方式就属于传统的web模型
,当我们点击submit按钮
之后,整个页面就会被刷新
一下。 -
form表单有三个很重要的属性,分别是
method
、action
和enctype
。 -
method,一般是get或者post;
-
action是我们要把数据传送到的地址;
-
enctype则是是
否对数据进行编码
。 -
enctype的默认值是 “application/x-www-from-urlencoded”,即在发送前编码所有字符,这个属性值即使我们不写也是默认这个的。
-
但是当我们在使用包含
文件上传控件
的表单的时候,这个值就必须更改成“multipart/from-data”
,即不对字符进行编码。 -
而在AJAX模型中,数据在客户端和服务器之间
独立传输
,服务器不在返回整个页面
。
AJAX优点
- 1、页面没有刷新,在页面内容内和服务器通信,给用户的体验好
- 2、通过异步的形式与服务器通信,不需要打断用户操作,给用户的体验更好
- 3、减轻服务器负担
- 4、不需要插件和小程序
AJAX缺点
1.不支持浏览器的后退。
2.安全问题,xss跨站点脚本攻击、sql注入攻击。
3.对搜索引擎支持较差seo。
4. 不支持移动端设备。
5. 违背url 和资源定位的初衷。
常见的Web攻击方式:SQL注入、XSS跨站脚本攻击、CSRF跨站点请求伪造
1、sql注入
原理
sql 注入就是通过sql命令插入到web 表单提交
或 输入域名
或 页面请求的查询字符串
, 最终达到欺骗服务器执行恶意的sql命令。
登陆操作sql:
-
select * from student where username=‘输入的用户名’ and password=‘输入的密码’
-
输入的用户名--> ' or '1' = '1' or '1' = '1
-
输入的密码--> 1 ' or '1 '=' 1
-
select * from student where username='' or '1' = '1' or '1' = '1' and password= "
-
select * from student where username='' and password='1' or '1'='1'
以上两个SQL语句的where条件
永远是成立的,所以验证永远是有效的.
输入的用户名 --> tom' ; drop table student- -
- select * from student where username='tom' ; drop table student--' and password=''
- 直接把student表给删除了(双连接符表示注释);
防御
1、不相信用户的输入,对用户的输入校验
、可以通过正则表达式
(必须数字,特定字符串,电话,email的正则),或限制长度
;对单引号
和双“-”
进行转换等
2、永远不要使用动态拼装sql
,可以使用参数化的sql
或者直接使用存储过程进行数据查询``存取
。哪怕参数是常量,也请用预编译语句PreparedStatement
,同时用占位符
,如: “select * from table where comment like ?”。
注意:如果参数不是使用的占位符
,即使用PreparedStatement
执行时也并不是预编译。
3、永远不要使用管理员权限的数据库连接
为每个应用
使用单独的有权限的数据库
连接,这样能降低数据库密码被泄漏而带来的破坏。
4、不要把机密信息
直接存放
加密
或者hash掉密码
和敏感的信息
;如数据库连接密码
、用户密码
、设备密码
需要加密存储
。
2 XSS跨站脚本攻击
2.1 原理
XSS(Cross Site Scripting)跨站脚本攻击
- 指攻击者在
网页中
嵌入客户端脚本(例如JavaScript)
- 当用户浏览此网页时,脚本就会在
用户的浏览器上执行
,从而达到攻击者的目的,比如获取用户的Cookie,导航到恶意网站,携带木马等。
1、Dom-Based XSS 漏洞
基于DOM的XSS,也就是web server不参与,仅仅涉及到浏览器的XSS. 攻击过程如下:小A发现了test.com中的Search.jsp页面有XSS漏洞,Search.jsp的代码如下:
<html>
<title></title>
<body>
Results for <%=request.getParameter("term")%>...
</body>
</html>
a准备: 1、偷取信息网址badboy.com 2、恶意url: test.com/search.asp?…)
方式: (邮件,QQ) 等方式给到 用户b.
小B点击了这个URL,嵌入在URL中的恶意Javascript代码
就会在小B的浏览器中
执行,那么小B在test.com网站
的cookie
,就会被发送到badboy网站
中,这样小B在test.com的信息
就被小A盗了
2、Stored XSS(存储式XSS漏洞)
如一个应用程序从数据库中查询数据
,在页面中显示出来,攻击者
在这个页面输入恶意的脚本数据
后,用户浏览此类页面
时就可能受到攻击,使得所有访问该页面的用户
都面临信息泄露的可能.
小C发现了网站A上有一个XSS 漏洞,该漏洞允许将攻击代码保存在数据库
中,于是小C发布了一篇文章
,文章中嵌入了恶意JavaScript代码
。其他人如小D访问这片文章的时候,嵌入在文章中的恶意Javascript代码
就会在小D的浏览器
中执行,其会话cookie
或者其他信息将被小C盗走。
Dom-Based XSS漏洞威胁用户个体,而存储式XSS漏洞所威胁的对象将是大量的用户。
防御措施
1、将重要的cookie标记为http only, 如果cookie中设置了HttpOnly属性,那么通过js脚本将无法读取到cookie信息,这样能有效的防止XSS攻击,窃取cookie内容,这样就增加了cookie的安全性,即便是这样,也不要将重要信息存入cookie。
2、输入过滤校验,对用户提交的数据进行有效性验证,仅接受指定长度范围内并符合我们期望格式的的内容提交。 过滤一些些常见的敏感字符,例如:< > ‘ “ & # \;过滤或移除特殊的Html标签, 例如: <script>, <iframe> , < for <, > for >, " for;过滤JavaScript 事件的标签,例如 "οnclick=", "onfocus" 等等。这里的数据校验除了前台要做,后台也要做。
3、DOM型的XSS攻击防御 把变量输出到页面时要做好相关的编码转义工作. 要输出到 <script>中,可以进行JS编码;要输出到HTML内容或属性,则进行HTML编码处理。根据不同的语境采用不同的编码处理方式。
3 CSRF跨站点请求伪造
CSRF( Cross-site request forgery )尽管听起来很像XSS跨站脚本攻击,CSRF则是通过伪装用户的请求
来访问一个用户已经认证
的站点,从而在并未授权
的情况下执行特定的操作。与XSS相比,CSRF攻击不大流行和难以防范
,所以比XSS更具危险性。
防范
1.目前主流的做法是使用CSRF Token抵御CSRF攻击
,在每个HTTP请求中
添加一个随机生成的Token值
,一般名为_csrf并且是hidden
的,然后由服务端验证
,验证通过才是有效的请求。
注意:_csrf的token值一般放在请求参数或请求头里
,不能放在cookie中,因为cookie包含在浏览器中可以被获取到。还有我们一般在更新操作才携带这个CSRF Token
,这样不会影响外部访问我们网站的查询操作,也不容易导致这个token泄漏,注意要求CSRF Token的更新操作要设计成幂等
的。
2.还有一种新兴的方法是使用cookie的SameSite
属性,即set-cookie指定属性,当一个来自外部的请求时不能携带cookie
。如
Set-Cookie: JSESSIONID=randomid; Domain=bank.example.com; Secure; HttpOnly; SameSite=Lax
- 1 SameSite的值有两个:
- Strict - 来自
同一站点的所有请求
都必须携带cookie,其他任何外部的请求
都不能携带cookie。 - Lax - 当来自
同一站点
或者顶级导航的请求,且该请求是
幂等时携带cookie`,否则其他任何请求不能携带cookie。
这样我们在安全的银行网站浏览
发出请求时可以携带JSESSIONID的cookie
,而来自外部恶意网站的请求就不能携带此cookie,服务器自然验证后
会拒绝该请求。
问题:
- 一个邮箱链接里
跳转到一个社交网站
时,不能携带cookie
会要求你再次登陆
,给用户带来不便。而且一些较老的浏览器可能不支持SameSite
属性。因此不建议使用SameSite作为防范CSRF的唯一方式。
一般如果服务提供的请求是给非浏览器端
使用的,不建议开启CSRF防御
。
http网络劫持与DNS劫持原理及预防
-
DNS 劫持 DNS服务器都是运营商分配的,所以在这个节点上,运营商可以为所欲为。 例如,访问jiankang.qq.com/index.html, 正常DNS应该返回腾讯的ip,而DNS劫持后,会返回一个运营商的中间服务器ip。访问该服务器会一致性的返回302,让用户浏览器跳转到预处理好的带广告的网页,在该网页中再通过iframe打开用户原来访问的地址。
-
类似DNS劫持返回302让用户浏览器跳转到另外的地址。(钓鱼网站就是这么干)
-
HTTP劫持 在运营商的
路由器节点
上,设置协议检测
,一旦发现是HTTP请求
,而且是html类型请求
,则拦截处理。 常见有两种:- 在服务器返回的HTML数据中插入js或dom节点(广告)
被劫持怎么办?
- 对于用户来说,最最直接的就是向运营商投诉。
- 在html 上加上
<meta http-equiv="Cache-Control" content="no-siteapp">
<meta http-equiv="Cache-Control" content="no-transform " />
百度官方给的禁止转码声明
。 - 最有用的方式,使用
HTTPS
,不让数据那么明显的裸奔。 https 加了SSL协议,会对数据进行加密
。 - 在开发的网页中加
代码过滤
,大概思路就是用JavaScript代码检查所有的外链
是否属于白名单
。
各种劫持的手段都有:
1. 直接返回一个带广告的HTML
2. 在原html中插入js,再通过js脚本安插广告;
3. iframe展示原来正常网页。
- js实际对抗
原文: www.cnblogs.com/kenkofox/p/… 1、对于DIV注入的,可以初始化时检查全部html代码。 2、对于js注入,可以在window监听DOMNodeInserted事件。 3、对于iframe的情况,要检测非常简单,只需要比较self和top是否相同。
回到ajax
AJAX 最重要的两个对象
- new XMLHttpRequest() 主流浏览器支持
- new ActiveXObject('Microsoft.XMLHTTP') Ie6 一下 ie. 永远滴神。
对象上三个重要的方法
open(method, url, flag?) 建立对服务器的调用,
- 第一个参数 method: get post put**
- 第二个参数url: 相对url 和绝对url
- 第三个可选参数 选择异步和同步, 异步是true;
send(content) 向服务器发送请求
setRequestHeader(lable, value) 指定首部, 设置任何首部之前调用open 方法
对象的属性
1、 onreadystatechange 状态改变触发器
2、 readyState 对象的状态(request)
0 代表 未初始化 此时已经创建一个XMLHttpRequest 对象
1 代表读取中,此时代码已经调用XMLHttpRequest的open 方法并且XMLHttprequest已将请求发送出去
2 代表已经读取 此时已经痛过open 方法把一个请求发送到服务端,但是还没有收到
3 代表交互中 此时已经收到http响应头部的信息,但是消息主体部分还没有收到
4 代表完成 此时响应已经被完全接受
3、responseText 服务器进程返回的数据的文本版本 4、responseXML 服务器进程返回的 数据的兼容DOM的XML文档对象 5、status 服务器返回的状态吗(response)
状态码的五种类别
- 1xx (信息类状态吗),接受的请求正在处理
- 2xx (成功状态码), 请求接受完毕
- 3xx (重定向状态码), 需要进行附加操作以完成请求
- 4xx (客户端错误状态码), 服务器无法请求
- 5xx (服务端错误状态码), 服务器处理请求出错
常用状态码
状态码参考原文: www.cnblogs.com/TankXiao/ar…
2xx
- 200 ok 请求已经被服务器正常处理
- 204 no Content 请求处理成功,但是没有资源可以返回
- 206 Partial Content 表示客户端进行了范围请求, 而服务器成功执行了这部分的GET 请求, content-Range 在首部里面
3xx
- 301 Moved Permanently 永久性重定向 请求的URL已移走。Response中应该包含一个Location URL, 说明资源现在所处的位置
- 302 Found 临时性重定向 类似301 客户端会使用Location中给出的URL,重新发送新的HTTP request
- 303 SeeOther 类似302
- 304 Not Modified 客户的缓存资源是最新的, 要客户端使用缓存
- 307 Temporary Redirect 临时重定向, 和302 的含义相同。
4xx 客户端错误
- 400 Bad Request 请求报文中存在请求错误
- 401 Unauthorized 未授权 需要需要通过HTTP 认证的认证信息
- 403 Forbidden 不允许访问该资源, 请求被服务器拒绝了,可能是token、cookie认证信息没有带
- 404 服务器没有该资源
5xx 服务器错误
- 500 Internal Server Error 服务端正在请求时候发生错误
- 503 Service Unavailable 服务器当机了,暂时处于超负荷或者停机维护,无法处理请求
状态吗大全
1xx
2xx
3xx
重定向状态码用来告诉浏览器客户端,它们访问的资源已被移动, Web服务器发送一个重定向状态码和一个可选的Location Header, 告诉客户端新的资源地址在哪。 浏览器客户端会自动用Location中提供的地址,重新发送新的Request。 这个过程对用户来说是透明的。
301和302 非常相似, 一个是永久转移,一个是临时转移。
(SEO中,搜索引擎如果碰到301, 比如网页A用301重定向到网页B,搜索引擎可以肯定网页A永久性改变地址,就会把网页B当做唯一有效目标)
302,303,307 是一样。 这是因为302是HTTP 1.0定义的, HTTP1.1中使用303,307. 同时又保留了302. (但在现实中,我们还是用302,我是没见过303和307) 所以这一节, 我们只需要掌握302, 304 就可以了。
4xx
5xx
有时候客户端发送了一条有效Request, Web服务器自身却出错了。 可能是Web服务器运行出错了, 或者网站都挂了
基于Promise的ajax 封装
低版本IE浏览器的缓存问题
问题:在低版本IE浏览器中,Ajax请求有严重的缓存问题,即在请求地址不发生变化的情况下,只有第一次请求会真正发送到服务器端。后续的请求都会从浏览器的缓存中获取结果,即使服务器的数据更新了,客户端依然拿到的是缓存中的旧数据。 解决:在请求地址后面加上参数,保证每一次请求参数的值不同
xhr.open("GET","http://xxx.xx?t="+new Date().getTime())
onload/onreadystatechange兼容性
如何中断请求
使用abort()方法可以中止正在进行的异步请求。在使用abort()方法前,应先清除onreadystatechange事件处理函数,因为IE和Mozilla在请求中止后也会激活这个事件处理函数,如果给onreadystatechange属性设置为null,则在IE会发生异常,所以可以为它设置一个空函数
xhr.onreadystatechange = function(){};
xhr.abort();
AJAX
function ajax(json) {
return new Promise((resove, reject) => {
let {url, method = 'get', flag, data} = json;
let xhr = null;
if(window.XMLHttpRequest) {
xhr = new window.XMLHttpRequest();
} else {
xhr = new ActiveXObject('Mircosoft.XMLHTTP');
}
const stringParam = getStringParam(data);
if(method == 'get') {
url = addQueryToUrl(stringParam, url);
xhr.open('get', url, flag)
} else {
xhr.open('post', url, flag)
}
// 不考虑兼容的话 用onload
xhr.onload = function() {
const result = {
status: xhr.status,
statusText: xhr.statusText,
headers: xhr.getAllResponseHeader(),
data: xhr.response || xhr.responseText,
}
if((xhr.status >= 200 $$ xhr.status < 300) || xhr.status === 304) {
resolve(result)
} else {
reject(result);
}
}
xhr.onreadystatechange = function() {
if(xhr.readyState === 4 && ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304)) {
const result = {
status: xhr.status,
statusText: xhr.statusText,
headers: xhr.getAllResponseHeader(),
data: xhr.response || xhr.responseText
}
resolve(result)
}
}
xhr.onerror = function() {
reject(nex TypeError('请求出错'))
}
xhr.timeout = function() {
reject(new TypeError('请求超时'))
}
xhr.onabort = function() {
reject(new TypeError('请求被终止'));
}
// 跨域携带cookie
xhr.withCredentials = true;
if(method === 'post') {
xhr.setRequestHeader("Content-type", "application/x-www-from-urlencoded");
xhr.send(stringParam);
}else {
xhr.send();
}
})
}
const addQueryToUrl = function(stringParam, url, isNeedTimestamp) {
if(!url) return '';
let _url = url;
// 有问号提出url并添加至obj,没问号用原url
if (url.indexOf('?') > -1) {
_url = url.split('?')[0];
}
let result = '?';
result += stringParam;
return `${_url}${result}${isNeedTimestamp ? `&t=new Date().getTime() : ''}`
}
const getStringParam = (param) {
if(!param || !Object.keys(param).length) return '';
let dataString = '';
for (const key in param) {
if(param[key] !== undefined && param[key] !== null) {
dataString += `${key}=${param[key]}&`;
}
}
// 去除最后一个& 并返回
return dataString.slice(0, -1);
}