Http与Https&跨域请求&表单重复提交

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/CoderYin/article/details/82698383

                             Http与Https&跨域请求&表单重复提交

一、http与https:

1、http和https的区别:

2、https的优缺点:

3、https原理:

我们都知道 HTTPS 能够加密信息,以免敏感信息被第三方获取,所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用 HTTPS 协议。

 客户端在使用 HTTPS 方式与 Web 服务器通信时有以下几个步骤,如图所示。

  (1)客户使用 https 的 URL 访问 Web 服务器,要求与 Web 服务器建立 SSL 连接。

  (2)Web 服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。

  (3)客户端的浏览器与 Web 服务器开始协商 SSL 连接的安全等级,也就是信息加密的等级。

  (4)客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站。

  (5)Web 服务器利用自己的私钥解密出会话密钥。

  (6)Web 服务器利用会话密钥加密与客户端之间的通信。

二、http请求模拟

1、httpClient:

1)、get方式:

            // 创建默认连接
			CloseableHttpClient httpClient = HttpClients.createDefault();
			// 创建get请求
			HttpGet httpGet = new HttpGet("get方式请求地址");
			CloseableHttpResponse response = httpClient.execute(httpGet);
			int code = response.getStatusLine().getStatusCode();
			// 获取状态
			System.out.println("http请求结果:" + code);
			if (code == 200) {
				System.out.println(EntityUtils.toString(response.getEntity()));
				//将string转换html框架
			}
			response.close();
			httpClient.close();

2)、post请求方式:

/**
	 * 发送 post请求访问本地应用并根据传递参数不同返回不同结果
	 */
	static public void post() {
		// 创建默认的httpClient实例.
		CloseableHttpClient httpclient = HttpClients.createDefault();
		// 创建httppost
		HttpPost httppost = new HttpPost("post方式请求地址");
		// 创建参数队列
		List<NameValuePair> formparams = new ArrayList<NameValuePair>();
		formparams.add(new BasicNameValuePair("userName", "yinyuyou"));
		UrlEncodedFormEntity uefEntity;
		try {
			uefEntity = new UrlEncodedFormEntity(formparams, "UTF-8");
			httppost.setEntity(uefEntity);
			System.out.println("executing request " + httppost.getURI());
			CloseableHttpResponse response = httpclient.execute(httppost);
			try {
				HttpEntity entity = response.getEntity();
				if (entity != null) {
					System.out.println("--------------------------------------");
					System.out.println("Response content: " + EntityUtils.toString(entity, "UTF-8"));
					System.out.println("--------------------------------------");
				}
			} finally {
				response.close();
			}
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e1) {
			e1.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			// 关闭连接,释放资源
			try {
				httpclient.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

3)、pom依赖导入:

 <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpclient -->
    <dependency>
	<groupId>org.apache.httpcomponents</groupId>
	<artifactId>httpclient</artifactId>
	<version>4.3.5</version>
    </dependency>

2、http请求工具postman:

3、Spring模拟HTTP请求—RestTemplate:

4、前端ajax请求:

$.ajax({
			type : 'post',
			dataType : "text",
			url : "http://a.a.com/a/FromUserServlet",
			data : "userName=yinyuyou&userAge=19",
			success : function(msg) {
				alert(msg);
			}
		});

三、长连接和短连接:

1、介绍:

在HTTP/1.0中,默认使用的是短连接:也就是说,浏览器和服务器每进行一次HTTP操作,就建立一次连接,但任务结束就中断连接。如果客户端浏览器访问的某个HTML或其他类型的 Web页中包含有其他的Web资源,如JavaScript文件、图像文件、CSS文件等;当浏览器每遇到这样一个Web资源,就会建立一个HTTP会话。

从 HTTP/1.1起,默认使用长连接:用以保持连接特性。使用长连接的HTTP协议,会在响应头有加入这行代码:Connection:keep-alive

在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的 TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接要客户端和服务端都支持长连接。

HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。

 

火狐浏览器查看每个接口的http协议和长短连接情况:

四、跨域请求

1、跨域介绍:

跨域介绍(针对ajax请求):跨域其实是浏览器安全机制请求访问的域名与ajax请求地址不一致,浏览器会直接无法返回请求结果。也就是说在a.a.com项目中访问b.b.com接口会产生跨域问题。

跨域原因产生:在当前域名请求网站中,默认不允许通过ajax请求发送其他域名。

报错信息:

2、解决方法:

1)使用后台response添加header:

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String userName = req.getParameter("userName");
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("userName", userName);
		resp.getWriter().println(jsonObject.toJSONString());
		// 使用后台response添加header:
		resp.setHeader("Access-Control-Allow-Origin", "*");
	}

2)使用JSONP:

前台ajax请求代码:

        $.ajax({
			type : "GET",
			async : false,
			url : "http://a.a.com/a/FromServlet?userName=131420",
            //dataType类型一定要是jsonp类型的
			dataType : "jsonp",
            //服务端用于接收callback调用的function名的参数
			jsonp : "jsonpCallback",
			success : function(data) {
				alert(data["userName"]);
			},
			error : function() {
				alert('fail');
			}
		});

后台servlet代码:

    @Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws         
ServletException, IOException {
		String userName = req.getParameter("userName");
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("userName", userName);
        //接受前台的jsonpCallback参数
		String jsonpCallback = req.getParameter("jsonpCallback");
		resp.getWriter().println(jsonpCallback+"("+jsonObject.toJSONString()+")");
	}

请求地址url:

总结:JSONP只支持get请求不支持post请求!

jsonp实现原理博客推荐http://www.cnblogs.com/wqhwe/p/5816941.html

 

3)内部通过httpclient转发:

实现步骤:ajax请求本网址后台接口,后台接口再访问目标网址接口返回结果给前台。

前台代码:

$(document).ready(function() {
		$.ajax({
			type : "GET",
			async : false,
			url : "http://b.b.com/b/FromServlet?userName=1314520",
			dataType : "json",
			success : function(data) {
				alert(data["userName"]);
			},
			error : function() {
				alert('fail');
			}
		});

	});

后台代码1(后台转发代码):

@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
           this.doPost(req, resp);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		// 创建默认连接
		CloseableHttpClient httpClient = HttpClients.createDefault();
		// 创建get请求
		HttpGet httpGet = new HttpGet("http://a.a.com/a/FromServlet?userName=" + req.getParameter("userName"));
		CloseableHttpResponse response = httpClient.execute(httpGet);
		int code = response.getStatusLine().getStatusCode();
		// 获取状态
		System.out.println("http请求结果:" + code);
		if (code == 200) {
			String result = EntityUtils.toString(response.getEntity());
			System.out.println(result);
			resp.getWriter().print(result);
			response.close();
			httpClient.close();
			// 将string转换html框架
		}

	}

后台代码2(目标接口代码):

@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String userName = req.getParameter("userName");
		JSONObject jsonObject = new JSONObject();
		jsonObject.put("userName", userName);
		resp.getWriter().println(jsonObject.toJSONString());
	}

4)使用接口网关:

使用nginx转发。

5)使用SpringCloud网关

五、防止表单重复提交

1、问题产生:

网络延迟、页面刷新、点击后退(重写加载)、回退

2、解决方法:使用token令牌

token令牌操作步骤:1、在打开表单的时候进入后台生成一个唯一的koken然后转发到表单提交页面中去(设置一个type为disable的input输入框),在表单提交的时候再次将改input框中的token拿出然后和session中进行比较,比较成功后就删除这样就可以从根本上防止表单重复提交。

代码介绍:

<form action="${pageContext.request.contextPath}/DoFormServlet"
		method="post" onsubmit="return isFlag()">
	<input type="hidden" value="${sessionToken}" name="sessionToken">
	用户名:<input type="text" name="userName">
	<input  on type="submit" value="提交"   id="submit">
	</form>
@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 生成一个唯一的uuid,存放在session中,其实在真正的项目中生成的令牌也就是token是放在redis中的
		String token = UUID.randomUUID().toString();
		req.getSession().setAttribute("sessionToken", token);
		req.getRequestDispatcher("from.jsp").forward(req, resp);
	}
@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		req.setCharacterEncoding("UTF-8");
		if(!isFlag(req)){
			resp.getWriter().write("fail");
			System.out.println("已经重复提交....");
			return;
		}
		String userName = req.getParameter("userName");
		try {
			Thread.sleep(300);
		} catch (Exception e) {
			// TODO: handle exception
		}
		System.out.println("往数据库插入数据...." + userName);
		resp.getWriter().write("success");
	}

	public boolean isFlag(HttpServletRequest request) {
		String token = request.getParameter("sessionToken");
		if (StringUtils.isEmpty(token)) {
			System.out.println("token为null");
			return false;
		}
		String sessionToken = (String) request.getSession().getAttribute("sessionToken");
		if (StringUtils.isEmpty(sessionToken)) {
			System.out.println("sessionToken为null,请不要重复提交..");
			return false;
		}
		if (!sessionToken.equals(token)) {
			System.out.println("请不要伪造token...sessionToken:" + sessionToken + ",token:" + token);
			return false;
		}
		//删除token
		 request.getSession().removeAttribute("sessionToken");
		return true;
	}

六、网页XSS攻击:

1、网络攻击手段:

SQL注入

XSS攻击(谷歌,360进行拦截,火狐没有拦截):(使用转义进行解决)

CSRF(模拟请求):(token+验证码防止人工重复提价表单)

DOS(压力测试):Nginx

XSS攻击(脚本注入):在A页面通过表单提交数据在B页面进行展示,人为的注入脚本字段从而破坏页面原始的展示内容。

代码介绍:

//表单页面
<form action="${pageContext.request.contextPath}/XssDemo" method="post">
	<input type="text" name="userName"/>
	<input type="submit">
</form>
//后台接受
@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String userName = req.getParameter("userName");
		req.setAttribute("userName", userName);
		req.getRequestDispatcher("showUserName.jsp").forward(req, resp);
	}
//数据展示页面
<body>
userName:${userName}
</body>
//如果你在表单页面输入 <script>location.href="https://www.baidu.com"</script> 他会直接跳转到该页面

使用转义进行解决:

//定义一个过滤器
public class XssFilter implements Filter{

	public void init(FilterConfig filterConfig) throws ServletException {
		
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		System.out.println("xssDofilter.....");
		HttpServletRequest req = (HttpServletRequest) request;
		XssHttpServletRequest xssHttpServletRequest = new XssHttpServletRequest(req);
		//放行
        chain.doFilter(xssHttpServletRequest, response);
        
	}

	public void destroy() {
		
	}
	

}

//定义一个参数处理类
public class XssHttpServletRequest extends HttpServletRequestWrapper{
	
	private HttpServletRequest request;

	public XssHttpServletRequest(HttpServletRequest request) {
		super(request);
		this.request = request;
	}
	
	@Override
	public String getParameter(String name) {
		String value = request.getParameter(name);
		System.out.println("没有转换:value"+value);
        //使用该工具类需要导包
		if(!StringUtils.isEmpty(value)) {
			value = StringEscapeUtils.escapeHtml4(value);
			System.out.println("转换过后:value"+value);
		}
		return value;
	}

}

pom文件,工具类需要
<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-lang3</artifactId>
			<version>3.4</version>
		</dependency>

//当然你还要在web.xml中进行过滤器定义

猜你喜欢

转载自blog.csdn.net/CoderYin/article/details/82698383