XSS攻击其实就是使用Javascript脚本注入进行攻击,因为浏览器默认支持脚本语言执行,如果在表单提交的时候,提交一些脚本参数,浏览器可能就直接执行了
攻击常见与论坛的评论
例如“提交表单后,展示到另一个页面”这个功能,可能会受到XSS脚本注入,本地cookie被读取,远程发送给黑客服务器端,然后可以伪造来发起请求
还可能会被这样的脚本重新定位,钓鱼网站就是这个思路,跳转到脚本里面的网站后,根据url里的银行卡账号密码,就把钱转到自己户下了
将脚本特殊字符,如<、>,转换成html源代码(<
为<)进行展示。
过程:编写一个过滤器拦截所有getParameter参数,重写httpservletwrapp方法,将参数特殊字符转换成html源代码保存,如>转换为>进行展示,这样就能防止XSS攻击了
// 重写HttpServletRequestWrapper 防止XSS攻击
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
private HttpServletRequest request;
/**
* @param request
*/
public XssHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
this.request = request;
}
@Override
public String getParameter(String name) {
// 过滤getParameter参数 检查是否有特殊字符
String value = super.getParameter(name);
System.out.println("value:" + value);
if (!StringUtils.isEmpty(value)) {
// 将中文转换为字符编码格式,将特殊字符变为html源代码保存
value = StringEscapeUtils.escapeHtml(value);
System.out.println("newValue:" + value);
}
return value;
}
}
SQL注入:利用现有应用程序,将(恶意)的SQL命令注入到后台数据库执行一些恶意的操作。
造成SQL注入的原因是因为程序没有有效过滤用户的输入,使攻击者成功的向服务器提交恶意的SQL查询代码,程序在接收后错误的将攻击者的输入作为查询语句的一部分执行,导致原始的查询逻辑被改变,额外的执行了攻击者精心构造的恶意代码(如or 1=1
)
如果程序代码中,dao层的sql语句如果使用sql语句拼接方式,那么就有可能会有注入的问题,因此建议传递参数时使用#,而不是$
#{}: 解析为一个 JDBC 预编译语句(prepared statement)的参数标记符,一个 #{ } 被解析为一个参数占位符,可以防止SQL注入问题。
${}: 仅仅为一个纯碎的 string 替换,在动态 SQL 解析阶段将会进行变量替换。
可以对二进制文件进行判断是否可以使用
比如A网站有一张图片/视频,被B网站直接通过img标签属性引入url,直接盗用A网站图片展示/视频播放的话是展示不了的
网关的黑名单/白名单权限判断的底层技术就是防盗链,限制只有合作(付费)的公司才可以调用我们的接口
存放资源的服务器会判断传过来的http请求头Referer域中的记录来源的值是否和此资源服务器规定可以访问的域名一致,如果不一致,则说明该图片可能被其他服务器盗用。
Referer字段中记录了访问的来源
@WebFilter(filterName = "imgFilter", urlPatterns = "/imgs/*")
public class ImgFilter implements Filter {
@Value("${domain.name}")
private String domainName;
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
String referer = req.getHeader("Referer");
if (StringUtils.isEmpty(referer)) {//png可自定义
request.getRequestDispatcher("/imgs/pdc .png").forward(request, response);
return;
}
String domain = getDomain(referer);
if (!domain.equals(domainName)) {//png可自定义
request.getRequestDispatcher("/imgs/pdc.png").forward(request, response);
return;
}
chain.doFilter(request, response);
}
public String getDomain(String url) {
String result = "";
int j = 0, startIndex = 0, endIndex = 0;
for (int i = 0; i < url.length(); i++) {
if (url.charAt(i) == '/') {
j++;
if (j == 2)
startIndex = i + 1;
else if (j == 3)
endIndex = i;
}
}
result = url.substring(startIndex, endIndex);
return result;
}
public void destroy() { }
}
CSRF(Cross Site Request Forgery, 跨站域请求伪造)是一种网络的攻击方式,是一种对网站的恶意利用,也是钓鱼网站的一种形式。
攻击方式几乎与XSS相反:XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。
与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。
幂等:保证数据唯一性,不允许有重复,即防止表单重复提交
多版本并发控制,该策略主要使用 update with condition(更新带条件来防止)来保证多次外部请求调用对系统的影响是一致的。在系统设计的过程中,合理的使用乐观锁,通过 version 或者 updateTime(timestamp)等其他条件,来做乐观锁的判断条件,这样保证更新操作即使在并发的情况下,也不会有太大的问题。例如
select * from tablename where condition=#condition# //取出带有版本versoin的要更新的对象
``update tableName set name=#name#,version=version+1 where version=#version#`
在更新的过程中利用 version 来防止,其他操作对对象的并发更新,导致更新丢失。
为了避免失败,通常需要一定的重试机制。
性能不太好
在插入数据的时候,插入去重表,利用数据库的唯一索引特性,保证唯一的逻辑。
性能不太好
select for update,整个执行过程中锁定该订单对应的记录。注意:这种在 DB 读大于写的情况下尽量少用。
业务要求:页面的数据只能被点击提交一次
发生原因:由于重复点击或者网络重发,或者 nginx 重发等情况会导致数据被重复提交
解决办法:
集群环境:采用 token 加 redis(redis 单线程的,处理需要排队)
单 JVM 环境:采用 token 加 redis 或 token 加 jvm 内存
处理流程:
数据提交前要向服务的申请 token,token 放到 redis 或 jvm 内存,token 有效时间
提交后后台校验 token,同时删除 token,生成新的 token 返回
token 特点:要申请,一次有效性,可以限流
客户端每次在调用接口的时候,需要在请求头中,传递令牌参数,每次令牌只能用一次。
一旦使用之后,此token就会被删除,客户端如果再传相同的token,就被因为在服务端找不到此token,报错“请勿重复提交”,这样就可以有效防止重复提交。
步骤:
1 生成令牌接口
public class TokenUtils {
private static Map<String, Object> tokenMap = new ConcurrentHashMap<>();
// 获取token
public static String getToken() {
synchronized(this){
// 1.生成令牌
String token = "token-" + System.currentTimeMillis();
}
// 2.存入tokenMap
tokenMap.put(token, token);
return token;
}
// 验证token,并且删除对应的token
public static Boolean exisToken(String token) {
// 1.从集合中获取token
Object result = tokenMap.get(token);
if (result == null) {
return false;
}
// 2.删除对应的token
tokenMap.remove(token);
return true;
}
}
2 接口中获取令牌验证
@RestController
public class TestController {
@Autowired
private TestService testService;
// 获取Token
@RequestMapping("/getToken")
public String getToken() {
return TokenUtils.getToken();
}
// 验证Token
@RequestMapping(value = "/addOrder", produces = "application/json; charset=utf-8")
public String test(@RequestBody OrderEntity orderEntity, HttpServletRequest request) {
String token = request.getHeader("token");
if (StringUtils.isEmpty(token)) {
return "参数错误!";
}
if (!TokenUtils.exisToken(token)) {
return "请勿重复提交!";
}
int result = testService.testAdd(orderEntity);
return result > 0 ? "测试成功" : "测试失败" + "";
}
}
防御CSRF,也可以看作成防止伪造Token请求攻击(如果黑客提前多次生成好token,再恶意多次提交)
使用图形验证码防止机器模拟接口请求攻击;
在调用核心业务接口时,比如支付、下单、等接口,最好使用手机短信验证验证或者是人脸识别,确认是本人在操作, 防止其他用户使用Token伪造请求。因为没有绝对防止抓包分析到token的方法
也可以使用Niginx做限流,或配置黑名单
绑定ip不合适,因为用户ip可能会变
黑客使用抓包工具分析Http请求,在忘记密码找回时,需要发送短信验证码(短信Code),如果验证码数字比较短的话,很容易使用暴力破解方式击破:假设验证码为4位数字,可以使用HttpClient启动多线程技术调用“找回密码”接口,暴力破解生成对应的4位数字以内的验证码进行验证,一旦验证成功,就破解好了
防御手段:
忘记密码验证码最好在6-8位,不要全是数字
一旦频繁调用接口验证时,应该使用图形验证码拦截,防止机器模拟。
使用黑名单和白名单机制,防御攻击。
配置防止DDos
对异常ip进行限流
在做值传递的时候最好不要使用隐藏域,如“找回密码”时输入的是别人的手机号,但是黑客修改了隐藏域的手机号,如传入黑客自己的手机,就把短信验证码传到自己的手机,结果就能把别人的密码改了
上传文件漏洞就是攻击者通过上传木马文件,直接得到WEBSHELL
导致该漏洞的原因在于代码没有对访客提交的数据进行检验或者过滤不严,可以直接提交修改过的数据绕过扩展名的检验。
需要验证文件流而不只是文件格式
操作:上传编写好的木马文件,如.jsp后缀的文件,里面的逻辑为循环删除所有文件,然后访问此文件的url即可
1)可以得到WEBSHELL
2)上传木马文件,会导致系统瘫痪
1 对文件格式限制,只允许某些格式上传
2 对文件格式进行校验,前端跟服务器都要进行校验(前端校验扩展名,服务器校验扩展名、Content_Type等)
3 将上传目录防止到项目工程目录之外,当做静态资源文件路径,并且对文件的权限进行设定,禁止文件下的执行权限。
4 上传图片的时候,一定要使用判断文件流的方式判断它一定是一张图片才能上传,不要通过判断后缀方式的方法
5 静态资源与动态资源分开服务器执行(Nginx+Tomcat实现动静分离),这样jsp就算经过伪装为静态文件(.html等),也会因为到达的是静态服务器,没有运行环境,所以无法执行(建议,这样也能起到加速的目的)
6 使服务器的硬盘无法做删除操作,不要有热部署功能(或限制上传class、jsp、exe等文件)
直接暴露 异常信息,会给攻击者以提示;
解决:可以使用mvc中的工具,把错误码异常等进行封装
HTML注释, 会暴露功能,方便攻击;
解决:上线时去除注释
文件上传,如果本身功能就是上传文件去执行,那么就有可能执行非常危险的命令;
解决:设置文件白名单,限制文件类型,另外还可以重新命名文件,改名为不可执行的
路径遍历,使用相对路径来遍历未开放的目录;
解决:方式是将JS,CSS部署在独立的服务器,使用独立域名, 其他文件不使用静态URL访问,动态参数不包含文件路径信息。