Android—构建安全的Android客户端请求,避免非法请求
2014-12-16 14:27
190 查看
今天通过实例来介绍一下如何构建安全的Android客户端请求,避免非法请求:
服务器端代码:
代码1—工具类:
package com.ghj.packageoftool;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 字符串SHA-1转换
*
* @author 高焕杰
*/
public class Sha1Util {
public static String SHA(String paramString) {
MessageDigest localMessageDigest;
try {
localMessageDigest = MessageDigest.getInstance("SHA-1");
localMessageDigest.update(paramString.getBytes());
return toHexString(localMessageDigest.digest()).toUpperCase();
} catch (NoSuchAlgorithmException localNoSuchAlgorithmException) {
localNoSuchAlgorithmException.printStackTrace();
return "";
}
}
private static String toHexString(byte[] digestArray) {
if (digestArray == null || digestArray.length <= 0) {
return "";
}
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < digestArray.length; i++) {
String hexString = Integer.toHexString(digestArray[i] & 0xFF);
if (hexString.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hexString);
}
return stringBuilder.toString();
}
public static void main(String[] paramArrayOfString) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String timeStamp = dateFormat.format(new Date());
String str = SHA("2014-12-16 10:19:30" + "miyue");
System.out.println(timeStamp + "signature:"+str.equals("927CFBFC8D0F049CEDB83FB10FBEC9AC784A9460"));
}
} 代码2—过滤器类:
package com.ghj.packageoffilter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ghj.packageoftool.Sha1Util;
/**
* 本过滤器用来校验请求是否合法
*
* @author 高焕杰
*/
public class CheckRequestFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String secretKey = "AndroidClient";
String timeStamp = request.getParameter("timeStamp");
String signature = request.getParameter("signature");
String dateDifference = getDateDifference(timeStamp);
if(dateDifference == null){//系统时间和时间戳的差值为null,这说明该请求中的时间被认为的进行了修改且时间格式不正确。
sendErrorState(response, 0);
}
if(!Sha1Util.SHA(timeStamp + secretKey).equals(signature)){//如果时间戳被人为地进行了修改造成请求签名不一致。
sendErrorState(response, 1);
}else if(Integer.parseInt(dateDifference) > 1000*60*5){//如果请求从创建到到达服务器端的时间大于5分钟,则认为请求超时——不给别有用心的人思考的时间
sendErrorState(response, 2);
}else{
chain.doFilter(request, response);
}
}
private void sendErrorState(HttpServletResponse response, int errorState) {
PrintWriter out = null;
try {
out = response.getWriter();
out.println("errorState:" + errorState);
out.flush();
} catch (IOException e) {
e.printStackTrace();
}finally{
out.close();
}
return;
}
/**
* @see: 获取时间戳与当前系统时间的差值(以毫秒为单位)
*
* @author GaoHuanjie
*/
private String getDateDifference(String timeStamp){
try{
if(timeStamp != null){
return String.valueOf(new Date().getTime()- new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(timeStamp).getTime());//获取系统时间(毫秒)-时间戳时间(毫秒)
}
}catch(Exception e){
e.printStackTrace();
}
return null;
}
public void destroy() {
}
public void init(FilterConfig filterConfig) throws ServletException {
}
} 代码3—Servlet类:
package com.ghj.packageofservlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ServerServlet extends HttpServlet {
private static final long serialVersionUID = -1052048925901833921L;
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/plain; charset=UTF-8");
request.setCharacterEncoding("UTF-8");
System.err.println(request.getParameter("clientData"));
PrintWriter printWriter = response.getWriter();
printWriter.print("您好Android客户端!");
printWriter.flush();
printWriter.close();
}
} 代码4—配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<filter>
<filter-name>checkRequestFilter</filter-name>
<filter-class>com.ghj.packageoffilter.CheckRequestFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>checkRequestFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>ServerServlet</servlet-name>
<servlet-class>com.ghj.packageofservlet.ServerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServerServlet</servlet-name>
<url-pattern>/ServerServlet.do</url-pattern>
</servlet-mapping>
</web-app> 客户端代码:
代码1—工具类:
与服务器端工具类完全一样!
代码1—Activity类:
package com.ghj.packageofactivity;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.http.Header;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import com.example.androidclient.R;
import com.ghj.packageoftool.Sha1Util;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;
public class AndroidClientActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.android_client);
Button sendInfoButton = (Button) findViewById(R.id.sendInfoButton);
sendInfoButton.setOnClickListener(new OnClickListener(){
@Override
@SuppressLint("SimpleDateFormat")
public void onClick(View v) {
String secretKey = "AndroidClient";
String timeStamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
RequestParams requestParams = new RequestParams();
requestParams.add("clientData", "您好服务器端!");
requestParams.add("timeStamp", timeStamp);
requestParams.add("signature", Sha1Util.SHA(timeStamp + secretKey));
new AsyncHttpClient().post("http://172.16.99.207:8080/CheckRequest/ServerServlet.do", requestParams, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
if(statusCode == 200){
String responseData = new String(responseBody);
if(responseData.contains("errorState")){
Toast.makeText(AndroidClientActivity.this, "请求非法!", Toast.LENGTH_LONG).show();
}else{
Toast.makeText(AndroidClientActivity.this, new String(responseBody), Toast.LENGTH_LONG).show();
}
}
}
@Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
Toast.makeText(AndroidClientActivity.this, "没有获取到Android服务器端的响应!", Toast.LENGTH_LONG).show();
}
});
}
});
}
} 总结:
1、由于该Demo客户端需要依赖很多文件和一些jar包,所以建议直接下载完整Demo工程——【0分下载Demo】
2、实现这个功能其实很简单:一句话,想尽一切方法让别有用心的人发出的请求失效!!!
服务器端代码:
代码1—工具类:
package com.ghj.packageoftool;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 字符串SHA-1转换
*
* @author 高焕杰
*/
public class Sha1Util {
public static String SHA(String paramString) {
MessageDigest localMessageDigest;
try {
localMessageDigest = MessageDigest.getInstance("SHA-1");
localMessageDigest.update(paramString.getBytes());
return toHexString(localMessageDigest.digest()).toUpperCase();
} catch (NoSuchAlgorithmException localNoSuchAlgorithmException) {
localNoSuchAlgorithmException.printStackTrace();
return "";
}
}
private static String toHexString(byte[] digestArray) {
if (digestArray == null || digestArray.length <= 0) {
return "";
}
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < digestArray.length; i++) {
String hexString = Integer.toHexString(digestArray[i] & 0xFF);
if (hexString.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hexString);
}
return stringBuilder.toString();
}
public static void main(String[] paramArrayOfString) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String timeStamp = dateFormat.format(new Date());
String str = SHA("2014-12-16 10:19:30" + "miyue");
System.out.println(timeStamp + "signature:"+str.equals("927CFBFC8D0F049CEDB83FB10FBEC9AC784A9460"));
}
} 代码2—过滤器类:
package com.ghj.packageoffilter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.ghj.packageoftool.Sha1Util;
/**
* 本过滤器用来校验请求是否合法
*
* @author 高焕杰
*/
public class CheckRequestFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String secretKey = "AndroidClient";
String timeStamp = request.getParameter("timeStamp");
String signature = request.getParameter("signature");
String dateDifference = getDateDifference(timeStamp);
if(dateDifference == null){//系统时间和时间戳的差值为null,这说明该请求中的时间被认为的进行了修改且时间格式不正确。
sendErrorState(response, 0);
}
if(!Sha1Util.SHA(timeStamp + secretKey).equals(signature)){//如果时间戳被人为地进行了修改造成请求签名不一致。
sendErrorState(response, 1);
}else if(Integer.parseInt(dateDifference) > 1000*60*5){//如果请求从创建到到达服务器端的时间大于5分钟,则认为请求超时——不给别有用心的人思考的时间
sendErrorState(response, 2);
}else{
chain.doFilter(request, response);
}
}
private void sendErrorState(HttpServletResponse response, int errorState) {
PrintWriter out = null;
try {
out = response.getWriter();
out.println("errorState:" + errorState);
out.flush();
} catch (IOException e) {
e.printStackTrace();
}finally{
out.close();
}
return;
}
/**
* @see: 获取时间戳与当前系统时间的差值(以毫秒为单位)
*
* @author GaoHuanjie
*/
private String getDateDifference(String timeStamp){
try{
if(timeStamp != null){
return String.valueOf(new Date().getTime()- new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(timeStamp).getTime());//获取系统时间(毫秒)-时间戳时间(毫秒)
}
}catch(Exception e){
e.printStackTrace();
}
return null;
}
public void destroy() {
}
public void init(FilterConfig filterConfig) throws ServletException {
}
} 代码3—Servlet类:
package com.ghj.packageofservlet;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ServerServlet extends HttpServlet {
private static final long serialVersionUID = -1052048925901833921L;
public void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {
doPost(request, response);
}
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/plain; charset=UTF-8");
request.setCharacterEncoding("UTF-8");
System.err.println(request.getParameter("clientData"));
PrintWriter printWriter = response.getWriter();
printWriter.print("您好Android客户端!");
printWriter.flush();
printWriter.close();
}
} 代码4—配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<filter>
<filter-name>checkRequestFilter</filter-name>
<filter-class>com.ghj.packageoffilter.CheckRequestFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>checkRequestFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>ServerServlet</servlet-name>
<servlet-class>com.ghj.packageofservlet.ServerServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServerServlet</servlet-name>
<url-pattern>/ServerServlet.do</url-pattern>
</servlet-mapping>
</web-app> 客户端代码:
代码1—工具类:
与服务器端工具类完全一样!
代码1—Activity类:
package com.ghj.packageofactivity;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.http.Header;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import com.example.androidclient.R;
import com.ghj.packageoftool.Sha1Util;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;
public class AndroidClientActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.android_client);
Button sendInfoButton = (Button) findViewById(R.id.sendInfoButton);
sendInfoButton.setOnClickListener(new OnClickListener(){
@Override
@SuppressLint("SimpleDateFormat")
public void onClick(View v) {
String secretKey = "AndroidClient";
String timeStamp = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
RequestParams requestParams = new RequestParams();
requestParams.add("clientData", "您好服务器端!");
requestParams.add("timeStamp", timeStamp);
requestParams.add("signature", Sha1Util.SHA(timeStamp + secretKey));
new AsyncHttpClient().post("http://172.16.99.207:8080/CheckRequest/ServerServlet.do", requestParams, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
if(statusCode == 200){
String responseData = new String(responseBody);
if(responseData.contains("errorState")){
Toast.makeText(AndroidClientActivity.this, "请求非法!", Toast.LENGTH_LONG).show();
}else{
Toast.makeText(AndroidClientActivity.this, new String(responseBody), Toast.LENGTH_LONG).show();
}
}
}
@Override
public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
Toast.makeText(AndroidClientActivity.this, "没有获取到Android服务器端的响应!", Toast.LENGTH_LONG).show();
}
});
}
});
}
} 总结:
1、由于该Demo客户端需要依赖很多文件和一些jar包,所以建议直接下载完整Demo工程——【0分下载Demo】
2、实现这个功能其实很简单:一句话,想尽一切方法让别有用心的人发出的请求失效!!!
相关文章推荐
- Android---网络交互之客户端请求服务端资源
- Android---网络交互之客户端请求服务端资源后续
- AvoidRepeatSubmit-通过Javascript避免客户端重复提交请求
- 构建Android Push Notification Service服务端及客户端[含代码]
- 构建Android Push Notification Service服务端及客户端
- 使用策略集构建符合 WS-security 安全规范的 JAX-WS Web Service 客户端
- Android Asynchronous Http Client-Android异步网络请求客户端接口
- Android客户端采用Http 协议Post方式请求与服务端进行数据交互
- android集合SSH搭建服务器客户端请求
- android客户端给服务端发post请求
- Android---网络交互之客户端请求服务端资源
- 5.腾讯微博Android客户端开发——获取请求用户授权Request Token .
- 5.腾讯微博Android客户端开发——获取请求用户授权Request Token
- Android学习笔记:Android客户端采用Hessian进行异步请求
- Android客户端采用Http 协议Post方式请求与服务端进行数据交互
- Android---网络交互之客户端请求服务端资源后续
- 5.腾讯微博Android客户端开发——获取请求用户授权Request Token
- Android集合SSH搭建服务器客户端请求
- Android客户端捕获http请求包的方法【转】
- android 客户端与服务端的通信 发送get和post请求并获取数据