赞
踩
在开放平台或者网关中,经常会见到appKey,appSecret和accessToken,这是用来对openApi访问的一种授权机制。一般分为调用方应用和发布方API,发布了API以后,是用来调用的。如果想调用API的话,需要创建一个调用方应用,同时会颁发一对appKey以及appSecret,前者是公开的,这就是你的唯一身份认证的,后者是密钥,一般不会公开,后续会用于加签,而且一般情况下也会支持重置。同时你这个应用可能需要购买申请想调用的API,当然也有免费的,其实就是说这个应用需要先得到某些API的授权才能够调用。其中常见的关键词如下:
其中app_key 和 app_secret 是一对出现的账号, 同一个 app_id 可以对应多个 app_key+app_secret, 这样 平台就可以分配你不一样的权限, 比如 app_key1 + app_secect1 只有只读权限 但是 app_key2+app_secret2 有读写权限… 这样你就可以把对应的权限 放给不同的开发者. 其中权限的配置都是直接跟app_key 做关联的, app_key 也需要添加数据库检索, 方便快速查找。通常情况下,app_key和app_secret用在通信的首次认证当中,认证完成平台会返回一个token(通常拥有失效时间),后续的交互通过该token即可。
至于为什么 要有app_key + app_secret 这种成对出现的机制呢, 因为 要加密, 通常在首次验证(类似登录场景) , 你需要用 app_key(标记要申请的权限有哪些) + app_secret(密码, 表示你真的拥有这个权限) 来申请一个token, 就是我们经常用到的 access_token, 之后的数据请求, 就直接提供access_token 就可以验证权限了。真正调用的时候,一般需要以下几步:
AppKey
和AppSecret
(需存在服务器端)AppKey
和AppSecret
在DB中有无记录,如果有,生成一串唯一的字符串(token
令牌),返回给服务器,服务器再返回给客户端其中关于第一点,可以采用签名的方式发送,当应用服务端向第三方服务端发请求时,带上AppKey
、时间戳、随机数、签名,签名可以使用 AppSecret
+ 时间戳 + 随机数使用sha1生成,第三方服务端收到后,生成本地签名和收到的签名比对,如果一致,校验成功.
对外开放的 API 接口都会面临一些安全问题,例如伪装攻击、篡改攻击、重放攻击以及数据信息泄漏的风险。利用 API 接口签名能方便的防范这些安全问题和风险。在设计 API 接口签名时主要考虑以下几点:
保证请求数据正确: 当请求中的某一个字段的值变化时,原有的签名结果就会发生变化。所以,只要参数发生变化,签名就要发生变化,否则请求将会是一个无效的请求。
保证请求来源合法: 一般情况下,生成签名的算法都会成对出现一个 appKey 和一个 appSecret,根据 appKey 能识别出调用者身份;根据 appSecret 能识别出签名是否合法。
识别接口的时效性: 一般情况下,签名和参数中会包含时间戳,这样服务端就可以验证客户端请求是否在有效时间内,从而避免接口被长时间的重复调用。
为了防止中间人攻击(客户端发来的请求被第三方拦截篡改),引入参数的签名机制。一般流程如下:
签名生成算法如下,由于请求的参数会作为签名的一部分,所以请求参数变化后,签名结果一定会随之发生变化,否则将无法认证通过;通过App Key 可以快速识别出API 调用者的身份,而无需与实际业务逻辑掺杂起来,通用性更强,如果有人劫持了请求,并对请求中的参数进行了修改,签名就无法通过;
1、调用方申请App Key 和 App Secret
2、在生成请求时,使用所有字母顺序排序后拼接的字符串 + App Secret 拼接后进行MD5加密,然后将 App Key, sign加密结果、时间戳追加到请求上。
3、服务收到请求后,根据App Key识别出调用方,然后从字典中查询到对应的App Secret,与请求参数拼接、加密,与请求中的签名进行对比,签名结果相同的为合法请求。同时通过时间戳可以判断是否为超时请求。
timestamp: 时间戳,是客户端调用接口时对应的当前时间戳,时间戳用于防止DoS攻击。当黑客劫持了请求的url去DoS攻击,每次调用接口时接口都会判断服务器当前系统时间和接口中传的的timestamp的差值,如果这个差值超过某个设置的时间(假如5分钟),那么这个请求将被拦截掉,如果在设置的超时时间范围内,是不能阻止DoS攻击的。timestamp机制只能减轻DoS攻击的时间,缩短攻击时间。如果黑客修改了时间戳的值可通过sign签名机制来处理。
sign机制可以防止参数被篡改,但无法防dos攻击(第三方使用正确的参数,不停请求服务器,使之无法正常提供服务)。因此,还需要引入时间戳机制。具体的操作为:客户端在形成sign值时,除了使用所有参数和token外,再加一个发起请求时的时间戳。即
sign值来源 = 所有非空参数升序排序+token+timestamp
而后端则需要根据当前时间和sign值的时间戳进行比较,差值超过一段时间则不予放行。
MD5: 是一种不可逆的摘要算法。论多少二进制数据,在MD5算法一定的情况下,都会变成一个定长的数据,并且是根据内容不同而唯一。
BASE64: 是一种编码方式,主要用于将二进制数据转换为文本数据,方便使用HTTP协议等,是可逆的。Base64是一种基于64个可打印字符来表示二进制数据的表示方法,是一种数据编码方式,是可逆的,它的编码方式是公开的,任何人可以直接通过索引表对编码后的数据解码,而且并不包含密钥。Base 64 Encoding有什么用?举个简单的例子,你使用SMTP协议 (Simple Mail Transfer Protocol 简单邮件传输协议)来发送邮件。因为这个协议是基于文本的协议,所以如果邮件中包含一幅图片,我们知道图片的存储格式是二进制数据(binary data),而非文本格式,我们必须将二进制的数据编码成文本格式,这时候Base 64 Encoding就派上用场了。Base64编码的作用:由于某些系统中只能使用ASCII字符。Base64就是用来将非ASCII字符的数据转换成ASCII字符的一种方法。它使用下面表中所使用的字符与编码。而且base64特别适合在http,mime协议下快速传输数据。base64其实不是安全领域下的加密解密算法。虽然有时候经常看到所谓的base64加密解密。其实base64只能算是一个编码算法,对数据内容进行编码来适合传输。虽然base64编码过后原文也变成不能看到的字符格式,但是这种方式很初级,很简单。Base64编码是从二进制值到某些特定字符的编码,这些特定字符一共64个,所以称作Base64。为什么不直接传输二进制呢?比如图片,或者字符,既然实际传输时它们都是二进制字节流。而且即使Base64编码过的字符串最终也是二进制(通常是UTF-8编码,兼容ASCII编码)在网络上传输的,那么用4/3倍带宽传输数据的Base64究竟有什么意义?真正的原因是二进制不兼容。某些二进制值,在一些硬件上,比如在不同的路由器,老电脑上,表示的意义不一样,做的处理也不一样。同样,一些老的软件,网络协议也有类似的问题。但是万幸,Base64使用的64个字符,经ASCII/UTF-8编码后在大多数机器,软件上的行为是一样的。有些情况下传输不可见字符不方便。比如一个纯文本协议,二进制中可能会出现被当做控制字符处理的部分。这样引起传输失败。
RSA: 1977年,三位数学家Rivest、Shamir 和 Adleman 设计了一种算法,可以实现非对称加密。这种算法用他们三个人的名字命名,叫做RSA算法。从那时直到现在,RSA算法一直是最广为使用的"非对称加密算法"。毫不夸张地说,只要有计算机网络的地方,就有RSA算法。RSA加密是一种非对称加密。可以在不直接传递密钥的情况下,完成解密。这能够确保信息的安全性,避免了直接传递密钥所造成的被破解的风险。是由一对密钥来进行加解密的过程,分别称为公钥和私钥。两者之间有数学相关,该加密算法的原理就是对一极大整数做因数分解的困难性来保证安全性。通常个人保存私钥,公钥是公开的(可能同时多人持有)。
私钥签名:其中私钥加密得到的密文实际上就是数字签名,要验证这个签名是否正确,只能用私钥持有者的公钥进行解密验证。使用数字签名的目的是为了确认某个信息确实是由某个发送方发送的,任何人都不可能伪造消息,并且,发送方也不能抵赖。在实际应用的时候,签名实际上并不是针对原始消息,而是针对原始消息的哈希进行签名,即:
signature = encrypt(privateKey, sha256(message))
对签名进行验证实际上就是用公钥解密:
hash = decrypt(publicKey, signature)
然后把解密后的哈希与原始消息的哈希进行对比。因为用户总是使用自己的私钥进行签名,所以,私钥就相当于用户身份。而公钥用来给外部验证用户身份。常用数字签名算法有:
SHA256: 对于任意长度的消息,SHA256都会产生一个256位的哈希值,称作消息摘要。这个摘要相当于是个长度为32个字节的数组,通常有一个长度为64的十六进制字符串来表示,其中1个字节=8位,一个十六进制的字符的长度为4位。SHA 加密算法的安全性要比 MD5 更高。 原理
DES: DES是一个分组加密算法,它以64位为分组对数据加密。64位一组的明文从算法的一端输入,64位的密文从另一端输出。DES是一个对称算法:加密和解密用的是同一算法。密钥的长度为56位。DES是对称的,也就是说它使用同一个密钥来加密和解密数据。通信双方同时掌握一个密钥,加密解密都是由一个密钥完成的(即加密密钥等于解密密钥,加解密密钥可以相互推倒出来)。双方通信前共同拟定一个密钥,不对第三方公开。
数字证书: 为了防止业务公钥在传输中被篡改,引入了可信的第三方来帮我们签名,即证书颁布机构(CA),CA 会将:证书的颁布机构、有效期、业务公钥、持有者(subject)等信息用 CA 的私钥进行签名。并且将签名结果和这些信息放在一起,这就叫做「数字证书」。明文和数字签名共同组成了数字证书。
接到证书的客户端,可以使用数字证书认证机构的公开密钥,对证书上的数字签名进行验证,一旦验证通过,客户端便明白两件事,一是认证服务器的公开密钥是真实有效的数字证书认证机构。二是服务器的公开密钥是值得信赖的。当客户端发起请求的时候,服务器将该数字证书发送给客户端,客户端将其中的加密密文(F3)通过CA机构提供的公钥及逆行解密后得到F2,同时将证书明文内容(F1)使用SHA1散列成F2,如果两者相等则说明证书没问题,服务端公钥没有被篡改。其实核心是利用ca机构私钥签名的证书验证服务公钥信息是否可信。 参考链接
中间人有可能篡改该证书吗?
假设中间人篡改了证书的原文,由于他没有CA机构的私钥,所以无法得到此时加密后签名,无法相应地篡改签名。浏览器收到该证书后会发现原文和签名解密后的值不一致,则说明证书已被篡改,证书不可信,从而终止向服务器传输信息,防止信息泄露给中间人。
中间人有可能把证书掉包吗?
假设有另一个网站B也拿到了CA机构认证的证书,它想劫持网站A的信息。于是它成为中间人拦截到了A传给浏览器的证书,然后替换成自己的证书,传给浏览器,之后浏览器就会错误地拿到B的证书里的公钥了,这确实会导致上文“中间人攻击”那里提到的漏洞?其实这并不会发生,因为证书里包含了网站A的信息,包括域名,浏览器把证书里的域名与自己请求的域名比对一下就知道有没有被掉包了。
接口的安全性主要围绕token、timestamp和sign三个机制展开设计,保证接口的数据不会被篡改和重复调用,下面具体来看:
Token授权机制: 用户使用用户名密码登录后服务器给客户端返回一个Token(通常是UUID),并将Token-UserId以键值对的形式存放在缓存服务器中。服务端接收到请求后进行Token验证,如果Token不存在,说明请求无效。Token是客户端访问服务端的凭证。
时间戳超时机制:用户每次请求都带上当前时间的时间戳timestamp,服务端接收到timestamp后跟当前时间进行比对,如果时间差大于一定时间(比如5分钟),则认为该请求失效。时间戳超时机制是防御DOS攻击的有效手段。
签名机制:将 Token 和 时间戳 加上其他请求参数再用MD5或SHA-1算法(可根据情况加点盐)加密,加密后的数据就是本次请求的签名sign,服务端接收到请求后以同样的算法得到签名,并跟当前的签名进行比对,如果不一样,说明参数被更改过,直接返回错误标识。签名机制保证了数据不会被篡改。
拒绝重复调用(非必须):客户端第一次访问时,将签名sign存放到缓存服务器中,超时时间设定为跟时间戳的超时时间一致,二者时间一致可以保证无论在timestamp限定时间内还是外 URL都只能访问一次。如果有人使用同一个URL再次访问,如果发现缓存服务器中已经存在了本次签名,则拒绝服务。如果在缓存中的签名失效的情况下,有人使用同一个URL再次访问,则会被时间戳超时机制拦截。这就是为什么要求时间戳的超时时间要设定为跟时间戳的超时时间一致。拒绝重复调用机制确保URL被别人截获了也无法使用(如抓取数据)。
首先介绍http head中的host、refer、origin 三个字段:
host:请求头指明了请求将要发送到的服务器主机名和端口号。
Referer
请求头包含了当前请求页面的来源页面的地址,即表示当前页面是通过此来源页面里的链接进入的。服务端一般使用 Referer
请求头识别访问来源,可能会以此进行统计分析、日志记录以及缓存优化等。Referer
指示了请求来自于哪个具体页面,包含服务器名和路径的详细URL,浏览器自动添加到http请求 Header 中,无需手动设置。
请求首部字段 Origin
指示了请求来自于哪个站点。该字段仅指示服务器名称,并不包含任何路径信息。该首部用于 CORS 请求或者 POST
请求。Origin
指示了请求来自于哪个站点,只有服务器名,不包含路径信息,浏览器自动添加到http请求 Header 中,无需手动设置。
CSRF(Cross-site request forgery),中文名称:跨站请求伪造。你这可以这么理解CSRF攻击:攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账…造成的问题包括:个人隐私泄露以及财产安全。其原理是攻击者构造网站后台某个功能接口的请求地址,诱导用户去点击或者用特殊方法让该请求地址自动加载。用户在登录状态下这个请求被服务端接收后会被误以为是用户合法的操作。
要完成一次CSRF攻击,攻击是利用受害者在被攻击网站的登录凭证,冒充受害者提交操作,仅仅是“冒用”,而不是直接窃取数据。攻击者预测出被攻击的网站接口的所有参数,成功伪造请求。受害者必须依次完成两个步骤:
1.登录受信任网站A,并在本地生成Cookie。
2.在不登出A的情况下,访问危险网站B。B诱导用户浏览器访问了A。
CSRF的两个特点:
防御方案:
1、验证码: 这个方案的思路是:每次的用户提交都需要用户在表单中填写一个图片上的随机字符串,这个方案可以完全解决CSRF,但个人觉得在易用性方面似乎不是太好。CSRF 攻击往往是在用户不知情的情况下成功伪造请求。而验证码会强制用户必须与应用进行交互,才能完成最终请求,而且因为 CSRF 攻击无法获取到验证码,因此通常情况下,验证码能够很好地遏制 CSRF 攻击。但验证码并不是万能的,因为出于用户体验考虑,不能给网站所有的操作都加上验证码。因此,验证码只能作为防御 CSRF 的一种辅助手段,而不能作为最主要的解决方案。
2、Cookie 的 SameSite 属性: 用来限制第三方 Cookie,从而减少安全风险,可以用来防止 CSRF 攻击和用户追踪。它可以设置三个值。
Lax
变为默认设置。这时,网站可以选择显式关闭SameSite
属性,将其设为None
。不过,前提是必须同时设置Secure
属性(Cookie 只能通过 HTTPS 协议发送),否则无效。3、同源检测: 在 HTTP 协议中,每一个异步请求都会携带两个 Header ,用于标记来源域名,这两个 Header 在浏览器发起请求时,大多数情况会自动带上,并且不能由前端自定义内容。 服务器可以通过解析这两个 Header 中的域名,确定请求的来源域。通过校验请求的该字段,我们能知道请求是否是从本站发出的。我们可以通过拒绝非本站发出的请求,来避免了 CSRF 攻击。
总的来说,同源检测是一个相对简单的防范方法,能够防范绝大多数的 CSRF 攻击,但这并不是万无一失的,对于安全性要求较高,或者有较多用户输入内容的网站,我们就要对关键的接口做额外的防护措施。
4、添加token
CSRF 攻击之所以能够成功,是因为攻击者可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 Cookie 中,因此攻击者可以在不知道这些验证信息的情况下直接利用用户自己的 Cookie 来通过安全验证。要抵御 CSRF,关键在于在请求中放入攻击者所不能伪造的信息,并且该信息不存在于 Cookie 之中。可以在 HTTP 请求中以参数的形式加入一个随机产生的 Token,并在服务器端建立一个拦截器来验证这个 Token,如果请求中没有 Token 或者 Token 内容不正确,则认为可能是 CSRF 攻击而拒绝该请求。
当客户端请求页面时,服务器会生成一个随机数Token,并且将Token放置到session当中,然后将Token发给客户端(一般通过构造hidden表单)。下次客户端提交请求时,Token会随着表单一起提交到服务器端。
盗链是指在自己的页面上展示一些并不在自己服务器上的一些内容, 获取别人的资源地址,绕过别人的资源展示页面,直接在自己的页面上向最终用户提供此内容。 一般被盗链的都是图片、 音乐、视频、软件等资源。通过盗链的手段可以减轻自己服务器的负担。通过Refer或者签名,网站可以检测目标网页访问的来源网页,如果是资源文件,则可以追踪到显示他的网页地址 一旦检测到来源不是本站,即进行阻止或者返回指定的页面。
CDN是比较场景的盗链场景:通过对App抓包或者反编译获取app上传cdn的域名地址,黑产就会上传自己的资源。
防御方案:
1、refer机制: 防盗链功能基于HTTP协议支持的Referer机制,通过referer跟踪来源,对来源进行识别和判断。用户访问加速域名网站内容时,访问请求到达CDN节点后,CDN节点会根据配置的referer黑白名单,对访问者的身份进行识别和过滤,符合规则的可以顺利访问到该内容。如果不符合规则,该访问请求将会被禁止,返回403禁止访问的错误信息。 Referer防盗链比较简单,当然Referer是可以伪造的。
2、时间戳防盗链: 主要是在url请求里,通过增加时间戳的信息来对url加上时间的因素,盗链者如果不及时更新url,那么就会无法访问。这个比较常见,但是如果盗链者定期的过来更新url,这种方法也会失效。
3、白名单: 配置请求者的IP黑白名单,设置黑名单之后,除了黑名单的用户都能访问;反之设置了白名单,只有白名单的用户都可以访问。
4、视频URL路径校验/KEY防盗链。基本思路:符合终端用户通过指定的URL向服务器请求资源,CDN缓存节点解析并分析请求URL中的防盗链参数并获取时间戳、时间校验级别、MD5 等参数;符合约定的规则正常提供业务并响应服务终端用户;不符合的终端用户请求资源,不符合约定的规则直接返回403; 允许开发者将视频的播放控制参数以 QueryString 的形式拼接在视频 URL 中,CDN 节点将检查 URL 中的播放控制参数,并依据参数控制视频的播放。目前,Key 防盗链通过“过期时间参数”、“允许播放的 IP 数量参数”和“试看时间参数”,支持“防盗链有效时间控制”、“防盗链播放人数控制”和“视频播放时长控制”。
防盗链 URL 的生成规则是在原始 URL 尾部,以 QueryString 的方式加入防盗链参数,形如:
http://example.vod.com/dir1/myVideo.mp4?t=[t]&exper=[exper]&rlimit=[rlimit]&us=[us]&sign=[sign]
这几个参数含义:
签名计算公式如下:sign = md5(KEY + t + exper + rlimit + us)
有人可能注意到了,怎么多了一个KEY?这个KEY就是我们的一个密钥,CDN和我们生成URL的服务器都要使用相同的KEY才能进行加密和解密配对,开启 URL 防盗链时填写的密钥。必须由大小写字母(a - Z)或者数字(0 - 9)组成,长度在8 - 20个字符之间。
例如视频原始地址:https://example.vod.com/dir1/myVideo.mp4,密钥KEY为:24FEQmTzro4V5u3D5epW,随机字符串us为72d4cd1101,URL 的过期时间是2018年01月31日20:00(Unix 时间为1517400000)即t为1517400000这里就不设置exper和limit了。
计算签名:sign = md5("24FEQmTzro4V5u3D5epW5a71afc072d4cd1101") = "01ad188259e1f34979c06a10e6d0fb89"
最后我们生成URL防盗链:http://example.vod.com/dir1/myVideo.mp4?t=5a71afc0&us=72d4cd1101&sign=01ad188259e1f34979c06a10e6d0fb89
总结:key 防盗链适用于具有时效性访问的资源文件,通过设置 key 密钥,配合签名过期时间来控制资源内容的访问时限。key 防盗链采用 md5 算法,将密钥、过期时间、文件路径等信息所计算的 md5 值加入到 URL 中,当 CDN 节点在验证请求时,除了验证过期时间,同时还会验证该 md5 值是否匹配,对于不匹配的 md5,即使请求未过期也会禁止访问。key 防盗链的过期时间可自行设置,如果你的网站有些内容,希望付费才能访问,且规定访问有有效期。就可以结合腾讯 key 防盗链来实现
sql注入是将Web页面的原URL、表单域或数据包输入的参数,修改拼接成SQL语句,传递给Web服务器,进而传给数据库服务器以执行数据库命令。如Web应用程序的开发人员对用户所输入的数据或cookie等内容不进行过滤或验证(即存在注入点)就直接传输给数据库,就可能导致拼接的SQL被执行,获取对数据库的信息以及提权,发生SQL注入攻击。
1、普通的sql拼接,是等到 参数都过来之后 才能确定 sql语句的,类似字符串拼接,比如最常见的:
select COUNT(*) from Users where Password = 'a' and UserName = 'b' or 1=1;
得等到 UserName 参数传过来,才会去 编译这条 sql语句(sql语句是编译后执行的),而这个时候, 这个拼接的sql 多了 or 选项,这是跟设计者本意相违背的。
有的黑客利用sql注入漏洞进行提权:提权就是通过各种办法和漏洞,提高自己在服务器中的权限,以便控制全局。数据库提权是指:通过执行数据库语句、数据库函数等方式提升服务器用户的权限。
union 运算符可以将两个或两个以上 select 语句的查询结果集合合并成一个结果集合显示,即执行联合查询。需要注意在使用 union 查询的时候需要和主查询的列数相同, 输入1' union select database(),user()#
进行查询 :按照Mysql语法,#后面会被注释掉,使用这种方法屏蔽掉后面的单引号,避免语法错误。
同理我们再输入 1' union select version(),@@version_compile_os#
进行查询:
2、参数化查询: 参数化查询是指在编写查询语句的时候,在需要参数的位置上使用参数占位符,然后查询的时候提供这一参数.
例如编译 这样一条sql, select COUNT(*) from Users where Password = @psw and UserName = @uname
,就跟函数的编译一样, 这样的话,以后'b' or 1='
只能作为 UserName 的参数了,相当于你去查 " ‘b’ or 1=1—’ " 这个用户,而不是 查 “b” 用户 或者 " 1=1 " 了。。。 相当于把 or 给屏蔽掉了。。。or 原来是sql的一项(普通的拼接).
SQL注入很多情况是增加查询语句,增加查询语句就会造成查询的语义发生变化(就是说编译会生成不同的东西)。如果使用参数化查询,在准备查询语句的时候数据库就去编译,然后提供参数就会重用这个编译结果,即使使用了注入变量,语义也不会发生变化(不会重新编译),同时,传参的时候,数据库也会将变量进行过滤,以达到防止注入的效果。
占位符: 在书写sql语句时,常常用?
作为占位符来使用,因为可以防止sql注入,所表示的内容不会被解析成sql的关键字,占位符就字面意思(即占位用的),通过传入参数或设定参数取代所占用的位置,完成字符串的拼接。这是用到了prepare statement
的方式,SQL已经预编译好了,然后替换中间的占位符,这个占位符在编译后就已经确定了它只是一个参数属性。因此,你用注入的代码去替换占位符,这个SQL也不会再进行编译了,所以也达不到注入的目的。
预编译: 数据库接受到sql语句之后,需要词法和语义解析,优化sql语句,制定执行计划。这需要花费一些时间。但是很多情况,我们的一条sql语句可能会反复执行,或者每次执行的时候只有个别的值不同
(比如query的where子句值不同,update的set子句值不同,insert的values值不同)。为了减少编译的方法,如果每次都需要经过上面的词法语义解析、语句优化、制定执行计划等,则效率就明显不行了。为了解决上面的问题,于是就有了预编译,预编译语句就是将这类语句中的值用占位符替代
,可以视为将sql语句模板化或者说参数化
。一次编译、多次运行,省去了解析优化等过程。
预编译的作用:
不会再进行SQL编译
。也就是说其后注入进来的参数系统将不会认为它会是一条SQL语句,而默认其是一个参数
,参数中的or或者and 等就不是SQL语法保留字了。实例:
// 错误
q := fmt.Sprintf("SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='%s' ORDER BY PRICE",
req.URL.Query()["category"])
db.Query(q)
// 正确
//使用?占位符
q := "SELECT ITEM,PRICE FROM PRODUCT WHERE ITEM_CATEGORY='?' ORDER BY PRICE"
db.Query(q, req.URL.Query()["category"])
在基于哈希加密的账户系统中,通常用户注册和认证的流程是这样的:
参考链接
如果直接对密码进行散列,那么黑客可以对通过获得这个密码散列值,然后通过查散列值字典(例如MD5密码破解网站),得到某用户的密码。
数据泄漏: 试想一下,如果我们的QQ账号密码都是明文存储在数据库的,那么如果一旦QQ的数据库信息泄漏了。我们的账号和密码信息是不是也泄漏了。那么获得这些信息的人就随意登录我们的QQ号的,这该是一件多么可怕的事情。或者每个数据库都需要有一些管理维护人员,也就是我们经常听到的DBA。他们的工作也就给了他们权限可以查看一些数据信息,那么大家的QQ用户名和密码就会暴露给他们。如果网站保管不当,就会被黑客攻击,你的密码就会泄漏出去。业界通常把窃取网站密码数据库的行为称为“拖库”。密码数据库一旦被攻陷,如果该网站的密码数据库未经加密,那你的密码就等同于裸露在黑客面前,之前爆出的“CSDN密码外泄门”就是明文储存密码,可即使网站做了加密处理,也同样有被破解的风险。sql注入等都是获取数据的手段。
随机字符串盐: 盐一般要求是固定长度的随机字符串,且每个用户的盐不同,比如10位,数据库可以这样存储:
username | password |salt
---------|---------—------------------------|----------
zp1996 |2636fd8789595482abf3423833901f6e |63UrCwJhTH
zpy |659ec972c3ed72d04fac7a2147b5827b |84GljVnhDT
采用的加密方式为:md5(md5(password) + salt)
加Salt可以一定程度上解决这一问题。所谓加Salt方法,就是加点“佐料”。其基本想法是这样的:当用户首次提供密码时(通常是注册时),由系统自动往这个密码里撒一些“佐料”,然后再散列。而当用户登录时,系统为用户提供的代码撒上同样的“佐料”,然后散列,再比较散列值,已确定密码是否正确。
查表和彩虹表的方式之所以有效是因为每一个密码的都是通过同样的方式来进行hash的。如果两个用户使用了同样的密码,那么一定他们的密码hash也一定相同。我们可以通过让每一个hash随机化,同一个密码hash两次,得到的不同的hash来避免这种攻击。
具体的操作就是给密码加一个随即的前缀或者后缀,然后再进行hash。这个随即的后缀或者前缀成为“盐”。正如上面给出的例子一样,通过加盐,相同的密码每次hash都是完全不一样的字符串了。检查用户输入的密码是否正确的时候,我们也还需要这个盐,所以盐一般都是跟hash一起保存在数据库里,或者作为hash字符串的一部分。盐不需要保密,只要盐是随机的话,查表,彩虹表都会失效。因为攻击者无法事先知道盐是什么,也就没有办法预先计算出查询表和彩虹表。如果每个用户都是使用了不同的盐,那么反向查表攻击也没法成功。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。