龙空技术网

08.如何保证API接口的安全性问题01

sungchungfoor 471

前言:

此时兄弟们对“ajax如何防止get乱码”可能比较着重,小伙伴们都需要知道一些“ajax如何防止get乱码”的相关知识。那么小编同时在网络上搜集了一些对于“ajax如何防止get乱码””的相关知识,希望小伙伴们能喜欢,看官们快快来了解一下吧!

1.互联网Api接口到底如何保证安全性问题?

2.代码落地实战防御XSS、CSRF攻击

3.代码落地如何防御接口数据被黑客抓包篡改?

4.接口数据加密对称还是非对称加密好

安全架构设计方案如何防御xss攻击

XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,但实际上也可以包括JavaVBScriptActiveX、 Flash 或者甚至是普通的HTML。攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容。 [1]

脚本攻击:利用JavaScript 注入 到后台数据库中,在通过展示数据加载该脚本 该脚本中(

1.使用js获取cookie信息(jwt)

2.将该jwt数据 上传黑客服务器(ajax)

获取jwt---用户会话信息 让后模拟请求形式使用该jwt登录。

xss攻击典型网站:论坛、评论区

;script>alert(‘ss’)</script>

;script type="text/javascript">

  window.location.href=";;

</script>

模拟xss攻击

前端传递 js 脚本到服务器端

{  "channel": "",  "equipment": "<script>alert('mayikt')</script>",  "password": "123456",  "phoneNumber": "15921009758"}

后端接口将该脚本存放数据库中

package com.mayikt.main.api.impl;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;import com.mayikt.common.core.api.BaseApiService;import com.mayikt.common.core.api.BaseResponse;import com.mayikt.main.api.UserLoginLogService;import com.mayikt.main.api.dto.res.UserLoginLogResDto;import com.mayikt.main.api.impl.entity.SysUserLoginLog;import com.mayikt.main.api.impl.mapper.SysUserLoginLogMapper;import org.springframework.beans.BeanUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.web.bind.annotation.CrossOrigin;import org.springframework.web.bind.annotation.RestController;import java.util.ArrayList;import java.util.List;/** * @ClassName UserLoginLogImpl */@RestController@CrossOriginpublic class UserLoginLogImpl extends BaseApiService<List<UserLoginLogResDto>> implements UserLoginLogService {    @Autowired    private SysUserLoginLogMapper sysUserLoginLogMapper;    @Override    public BaseResponse<List<UserLoginLogResDto>> getUserLoginLog() {        // 模拟查询登录的日志记录        List<SysUserLoginLog> sysUserLoginLogs = sysUserLoginLogMapper.selectList(new QueryWrapper<>());        List<UserLoginLogResDto> userLoginLogResDtos = new ArrayList<>();        for (int i = 0; i < sysUserLoginLogs.size(); i++) {            UserLoginLogResDto userLoginLogResDto = new UserLoginLogResDto();            BeanUtils.copyProperties(sysUserLoginLogs.get(i), userLoginLogResDto);            userLoginLogResDtos.add(userLoginLogResDto);        }        return setResultSuccessData(userLoginLogResDtos);    }}package com.mayikt.main.api;import com.mayikt.common.core.api.BaseResponse;import com.mayikt.main.api.dto.res.UserLoginLogResDto;import org.springframework.web.bind.annotation.GetMapping;import java.util.List;/** * @ClassName UserLoginLogService */public interface UserLoginLogService {    @GetMapping("/getUserLoginLog")    BaseResponse<List<UserLoginLogResDto>> getUserLoginLog();}

前端html

<!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>xss模拟攻击</title></head><script src=";        type="text/javascript" charset="utf-8"></script><script>    function bt1() {        $.ajax({            url: ";, success: function (result) {                var code = result.code;                if (code == 200) {                    var arrays = result.data;                    var equipment = arrays[0].equipment;                    $("#dv1").html(equipment);                }            }        });    }</script><body><input id="bt" type="button" value="提交数据" onclick="bt1()"><div id="dv1"></div></body></html>

防御xss方式1

将用户前端所提交的参数进行过滤。

<script>alert('ss')</script>

<script>alert('ss')</script>

html 大于> 小于号 <

<>

<script>alert('ss')</script>

 String equipment = loginUserReqDto.getEquipment();        loginUserReqDto.setEquipment(StringUtils.isEmpty(equipment) ? null : StringEscapeUtils.escapeHtml(equipment));        SysUserLoginLog sysUserLoginLog = new SysUserLoginLog(sysUser.getId(), IPUtils.getIpAddr(request),                new Date(), token,                loginUserReqDto.getChannel(), loginUserReqDto.getEquipment());

该方式的缺陷:每个参数都需要像这样写 代码非常冗余

        String str = "<script>alert('ss')</script>";        String s = StringEscapeUtils.escapeHtml(str);        System.out.println(s);
方式2

接口接受参数 ?传递参数形式---

传递参数都是json数据形式

spring mvc 接受 json数据提供 api回调

package com.mayikt.main.security;import com.fasterxml.jackson.core.JsonParser;import com.fasterxml.jackson.core.JsonProcessingException;import com.fasterxml.jackson.databind.DeserializationContext;import com.fasterxml.jackson.databind.JsonDeserializer;import com.fasterxml.jackson.databind.ObjectMapper;import com.fasterxml.jackson.databind.module.SimpleModule;import com.google.common.net.MediaType;import org.apache.commons.lang.StringEscapeUtils;import org.apache.commons.lang.StringUtils;import org.springframework.context.annotation.Configuration;import org.springframework.http.converter.HttpMessageConverter;import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;import java.io.IOException;import java.util.ArrayList;import java.util.List;import java.util.ListIterator;/** * 解决post 请求传递json数据 防御xss攻击 */@Configurationpublic class WebMvcConfig extends WebMvcConfigurationSupport {    @Override    public void addResourceHandlers(ResourceHandlerRegistry registry) {        registry.addResourceHandler("swagger-ui.html")                .addResourceLocations("classpath:/META-INF/resources/");        registry.addResourceHandler("/webjars/**")                .addResourceLocations("classpath:/META-INF/resources/webjars/");    }    @Override    protected void extendMessageConverters(List<HttpMessageConverter<?>> messageConverters) {        /**         * 替换默认的MappingJackson2HttpMessageConverter,过滤(json请求参数)xss         */        ListIterator<HttpMessageConverter<?>> listIterator = messageConverters.listIterator();        while (listIterator.hasNext()) {            HttpMessageConverter<?> next = listIterator.next();            if (next instanceof MappingJackson2HttpMessageConverter) {                listIterator.remove();                break;            }        }        messageConverters.add(getMappingJackson2HttpMessageConverter());    }    public MappingJackson2HttpMessageConverter getMappingJackson2HttpMessageConverter() {        // 创建自定义ObjectMapper        SimpleModule module = new SimpleModule();        module.addDeserializer(String.class, new JsonHtmlXssDeserializer(String.class));        ObjectMapper objectMapper = Jackson2ObjectMapperBuilder.json().applicationContext(this.getApplicationContext()).build();        objectMapper.registerModule(module);        // 创建自定义消息转换器        MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();        mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);        return mappingJackson2HttpMessageConverter;    }}/** * 对入参的json进行转义 */class JsonHtmlXssDeserializer extends JsonDeserializer<String> {    public JsonHtmlXssDeserializer(Class<String> string) {        super();    }    @Override    public Class<String> handledType() {        return String.class;    }    @Override    public String deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)            throws IOException, JsonProcessingException {        String value = jsonParser.getValueAsString();        if (!StringUtils.isEmpty(value)) {            return StringEscapeUtils.escapeHtml(value);        }        return value;    }}
抓包如何防止篡改数据Fiddler抓包工具的使用

1.可以使用第三方抓包工具,对请求前后实现代理,可以修改参数请求内容和参数响应内容,抓包工具http调试工具

2.Fiddler4下载地址:

使用Fiddler4篡改请求之前:

防御篡改数据

使用MD5可以直接验证签名参数 MD5 属于单向加密,只能够暴力破解。

MD5应用场景 在nacos分布式配置中心中,使用MD5 比对文件内容是否发生改变

HasherPro比对文件内容是否发生改变。

MD5在线暴力破解地址:

String userName="123456";

System.out.println( DigestUtils.md5Hex(userName));

黑客如何破解?自己需要根据参数内容 生成签名

如果只是改了参数内容---没有用的 所以我们需要该签名

{"password":"123456","phoneNumber":"phoneNumber","channel":"安卓","equipment":"<script>alert('mayikt')</script>"}

{sign=325ab041d4889825a46d1e1e802ab5de, timestamp=1652537015771}

package com.mayikt.main.security;import com.alibaba.fastjson.JSONObject;import com.alibaba.fastjson.JSONPObject;import org.apache.commons.codec.digest.DigestUtils;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.io.UnsupportedEncodingException;import java.net.URLEncoder;import java.util.*;/** * 参数验证签名 */public class SignUtil {    private static Logger logger = LoggerFactory.getLogger(SignUtil.class);    /**     * 加密密钥     */    private final static String APP_KEY = "mykey123456";    public final static String SECRET_KEY = "mysecret123456";    /**     * 字符编码     */    private final static String INPUT_CHARSET = "UTF-8";    /**     * 超时时间     */    private final static int TIME_OUT = 30 * 60 * 1000;    /**     * 请求参数Map转换验证Map     *     * @param requestParams 请求参数Map     * @param charset       是否要转utf8编码     * @return     * @throws UnsupportedEncodingException     */    public static Map<String, String> toVerifyMap(Map<String, String[]> requestParams, boolean charset) {        Map<String, String> params = new HashMap<>();        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {            String name = (String) iter.next();            String[] values = requestParams.get(name);            String valueStr = "";            for (int i = 0; i < values.length; i++) {                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";            }            // 乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化            if (charset)                valueStr = getContentString(valueStr, INPUT_CHARSET);            params.put(name, valueStr);        }        return params;    }    /**     * 除去数组中的空值和签名参数     *     * @param sArray 签名参数组     * @return 去掉空值与签名参数后的新签名参数组     */    public static Map<String, String> paraFilter(Map<String, String> sArray) {        Map<String, String> result = new HashMap<>();        if (sArray == null || sArray.size() <= 0) {            return result;        }        for (String key : sArray.keySet()) {            String value = sArray.get(key);            if (value == null || value.equals("") || key.equalsIgnoreCase("sign")) {                continue;            }            result.put(key, value);        }        return result;    }    /**     * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串     *     * @param params 需要排序并参与字符拼接的参数组     * @return 拼接后字符串     */    public static String createLinkString(Map<String, String> params) {        return createLinkString(params, false);    }    /**     * 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串     *     * @param params 需要排序并参与字符拼接的参数组     * @param encode 是否需要UrlEncode     * @return 拼接后字符串     */    public static String createLinkString(Map<String, String> params, boolean encode) {        List<String> keys = new ArrayList<>(params.keySet());        Collections.sort(keys);        String prestr = "";        for (int i = 0; i < keys.size(); i++) {            String key = keys.get(i);            String value = params.get(key);            if (encode)                value = urlEncode(value, INPUT_CHARSET);            if (i == keys.size() - 1) {// 拼接时,不包括最后一个&字符                prestr = prestr + key + "=" + value;            } else {                prestr = prestr + key + "=" + value + "&";            }        }        return prestr;    }    /**     * 编码转换     *     * @param content     * @param charset     * @return     * @throws UnsupportedEncodingException     */    private static byte[] getContentBytes(String content, String charset) {        if (charset == null || "".equals(charset)) {            return content.getBytes();        }        try {            return content.getBytes(charset);        } catch (UnsupportedEncodingException e) {            throw new RuntimeException("MD5签名过程中出现错误,指定的编码集不对,您目前指定的编码集是:" + charset);        }    }    /**     * 编码转换     *     * @param content     * @param charset     * @return     */    private static String getContentString(String content, String charset) {        if (charset == null || "".equals(charset)) {            return new String(content.getBytes());        }        try {            return new String(content.getBytes("ISO-8859-1"), charset);        } catch (UnsupportedEncodingException e) {            throw new RuntimeException("指定的编码集不对,您目前指定的编码集是:" + charset);        }    }    /**     * URL转码     *     * @param content     * @param charset     * @return     */    private static String urlEncode(String content, String charset) {        try {            return URLEncoder.encode(content, charset);        } catch (UnsupportedEncodingException e) {            throw new RuntimeException("指定的编码集不对,您目前指定的编码集是:" + charset);        }    }    /**     * 生成要请求的签名参数数组     *     * @return 要请求的签名参数数组     */    public static Map<String, String> signJson(String json) {        // 时间戳加入签名参数组中        HashMap<String, String> sParaTemp = new HashMap<>();        sParaTemp.put("timestamp", String.valueOf(System.currentTimeMillis()));        // 生成签名结果        String mysign = DigestUtils.md5Hex(getContentBytes(json, INPUT_CHARSET));        // 签名结果加入请求提交参数组中        sParaTemp.put("sign", mysign);        return sParaTemp;    }    public static boolean verifyJson(String json, String sign, String timestamp) {        // 将json数据做一个格式化        JSONObject data = JSONObject.parseObject(json);        // 获得签名验证结果        String mysign = DigestUtils.md5Hex(getContentBytes(json, INPUT_CHARSET));        if (mysign.equals(sign)) {            // 是否超时            long curr = System.currentTimeMillis();            if ((curr - Long.valueOf(timestamp)) > TIME_OUT) {                logger.info("api is time out");                return false;            }            return true;        } else {            return false;        }    }    public static void main(String[] args) {        JSONObject jsonObject = new JSONObject();        jsonObject.put("channel", "ios");        jsonObject.put("equipment", "<script>alert('mayikt')</sript>");        jsonObject.put("password", "123456");        jsonObject.put("phoneNumber", "phoneNumber");        String json = jsonObject.toJSONString();        System.out.println(json);        Map<String, String> stringStringMap = signJson(json);        System.out.println(stringStringMap);    }}package com.mayikt.main.security;import com.alibaba.fastjson.JSONObject;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Component;import javax.servlet.*;import javax.servlet.annotation.WebFilter;import javax.servlet.http.HttpServletRequest;import java.io.IOException;import java.io.PrintWriter;@Component@WebFilter()@Slf4jpublic class SignFilter implements Filter {    @Override    public void init(FilterConfig filterConfig) throws ServletException {    }    @Override    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {        // 拦截请求,验证json数据 签名        RequestWrapper requestWrapper = new RequestWrapper((HttpServletRequest) request);        String json = requestWrapper.getBody();        // 验证token        HttpServletRequest req = (HttpServletRequest) request;        String sign = req.getHeader("sign");        String timestamp = req.getHeader("timestamp");        boolean result = SignUtil.verifyJson(json, sign, timestamp);        if (!result) {            PrintWriter writer = response.getWriter();            JSONObject data = new JSONObject();            data.put("code", "500");            data.put("msg", "验证签名失败");            writer.println(data.toJSONString());            writer.close();            return;        }        chain.doFilter(requestWrapper, response);    }    @Override    public void destroy() {    }}package com.mayikt.main.security;import lombok.extern.slf4j.Slf4j;import javax.servlet.ReadListener;import javax.servlet.ServletInputStream;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletRequestWrapper;import java.io.BufferedReader;import java.io.ByteArrayInputStream;import java.io.IOException;import java.io.InputStreamReader;@Slf4jpublic class RequestWrapper extends HttpServletRequestWrapper {    private final String body; // 报文    public RequestWrapper(HttpServletRequest request) throws IOException {        super(request);        BufferedReader streamReader = new BufferedReader(                new InputStreamReader(request.getInputStream(), "UTF-8"));        StringBuilder responseStrBuilder = new StringBuilder();        String inputStr;        while ((inputStr = streamReader.readLine()) != null) {            responseStrBuilder.append(inputStr);        }        body = responseStrBuilder.toString();        log.info("body:{}", body);    }    public String getBody() {        return body;    }    @Override    public BufferedReader getReader() throws IOException {        return new BufferedReader(new InputStreamReader(getInputStream()));    }    @Override    public ServletInputStream getInputStream() throws IOException {        final ByteArrayInputStream bais = new ByteArrayInputStream(body.getBytes("utf-8"));        return new ServletInputStream() {            @Override            public boolean isFinished() {                return false;            }            @Override            public boolean isReady() {                return false;            }            @Override            public void setReadListener(ReadListener readListener) {            }            @Override            public int read() throws IOException {                return bais.read();            }        };    }}
相关代码

m5.rar

标签: #ajax如何防止get乱码