精华内容
下载资源
问答
  • JAVA安全编码规范

    千次阅读 2019-05-13 01:03:00
    java线程安全规范 一般用同步方法、同步代码块来锁定对象 private Lock lock = new ReentrantLock(); 先用lock.lock()方法锁,在finally代码块中调unlock方法进行解锁 ====以上都为即兴发挥,不对之处感谢指出==...

    空串或空对象判断

    1. 空字符串的判断一般都用StringUtils.isEmpty()方法,判断集合是否为空用CollectionUtills
    2. 比较对象或字符串,已知对象.equals(传入对象)
    3. 随机数,计算机中没有现实意义上的随机数,在入门时常用为Math.random(int seed)方法,他会返回一个0~1之间的double型数字。然而当seed的数量一致时,每次生成的随机数都是一样的,即
    for (int i = 0;i<10;i++){
     System.out.print(Math.random(2));
    }
    for (int i = 0;i<10;i++){
     System.out.print(Math.random(2));
    }
    

    这两个循环生成同样的随机数,故称伪随机数。开发中用java.security.secureRandom类来生成强随机数。 4. 有关金额这种精度要求很高的四则运算需要用BigDecimal类,提供了加减乘除,四舍五入等多种运算,防止基本数据类型造成的精度丢失。

    敏感数据加密

    1. 网络协议上,https比http好:具体好在哪。。嗯 多了s,加密协议
    2. 公钥和私钥~
    3. java程序报错时,不能在网页上输出Exception信息,拦截所有异常跳统一界面,防止暴露系统信息。
    4. 线程同步对象构造私有并final,sychonized或lock,防止用实例锁控制静态变量
    5. 信息传输 加salt盐,MD5,非对称加密等。
    6. 用SSLSOCKET (有SSL安全协议)代替SOCKET,
    7. 关键字段可以加上@Transient修饰,编译时跳过该属性

    信息安全攻防

    1. sql注入、OS命令写入、java执行命令行
    2. xxs跨域攻击
    3. xml注入
    4. json注入

    java线程安全规范

    1. 一般用同步方法、同步代码块来锁定对象
    2. private Lock lock = new ReentrantLock(); 先用lock.lock()方法锁,在finally代码块中调unlock方法进行解锁 ====以上都为即兴发挥,不对之处感谢指出====

    转载于:https://my.oschina.net/xlpapapa/blog/3048691

    展开全文
  • [转]陌陌Java安全编码规范

    千次阅读 2021-02-25 10:09:41
    陌陌Java安全编码规范 https://github.com/momosecurity/rhizobia_J JAVA安全编码规范 目录 1、安全编码基本原则 1.1 所有输入数据都是有害的 1.2 不依赖运行环境的安全配置 1.3 安全控制措施落实在最后执行阶段 ...

    陌陌Java安全编码规范
    https://github.com/momosecurity/rhizobia_J

    JAVA安全编码规范

    1、安全编码基本原则

    1.1 所有输入数据都是有害的

    直接输入数据:
    对于用户通过 GET, POST, COOKIE, REQUEST等输入的数据以及框架提供的数据来源,即通信协议中从客户端传过来的一切变量,无论是用户手动填写的数据或是客户端浏览器或操作系统自动填写的数据,都可能产生安全问题,需要进行严格的安全性检查。

    间接的输入数据:
    从数据库、文件、网络、内部API获取的数据等,即一些不直接来源于用户,但是又不是程序中定义好的常量数据。比如用户的输入经过层层转化输出到数据库或文件,后面又再次利用的时候,这时获得的数据依然是不可信的,同样需要进行严格的安全性检查。

    1.2 不依赖运行环境的安全配置

    ​ 不能寄希望于配置文件的安全选项,必须将程序置身于最不安全的配置下进行考虑。

    1.3 安全控制措施落实在最后执行阶段

    ​ 每个安全问题都有其产生的原因,例如SQL注入的原因是SQL语句参数拼接。因此对SQL注入问题的防范,需要在SQL语句执行前对参数进行安全处理,因为此时才能确定预期的参数数据类型、数据范围等。

    1.4 最小化

    ​ 最小化原则适用于所有安全相关的领域,在代码安全方面主要表现为:
    1、用户输入最小化。尽可能少地使用用户的输入。
    2、用户输入范围最小化。过滤参数时应使用白名单策略,对于可明确定义范围的参数检查参数的有效性,譬如Email,卡号,身份证号等。
    3、返回信息最小化。程序错误信息等应对用户屏蔽,不要将原始错误信息直接返回到用户侧。

    1.5 失败终止

    ​ 对用户提交的数据进行安全性检查的时候,如果发现数据不符合要求应终止业务的执行,不要试图修正和转换用户提交的参数继续向下执行。

    2、常见漏洞对应的安全编码方法

    命令注入

    正解编码方法:

    1. 精确匹配用户提交数据
    String ip = request.getParameter("ip");
    if(null==ip){
        //handle error
    }
    Boolean ret = Pattern.matches("((?:(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d)\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d?\\d))", ip);
    if(!ret){
       //handle error
    }
    String[] cmd = new String[]{"ping", "-c", "2", ip};
    Runtime rt = Runtime.getRuntime();
    Process proc = rt.exec(cmd);
    
    1. 使用白名单
    String dir=request.getParameter("dir");
    if(null==dir){
        //handle error
    }
    switch (dir){
        case "test1":dir="test1";
            break;
        case "test2":order_by="test2";
            break;
        default:order_by="test";  
    }
    Runtime runtime=Runtime.getRuntime();
    Process process=runtime.exec(new String[]{"ls ", dir});
    int result=process.waitFor();
    //do something
    

    代码注入

    正解编码方法:

    应使用白名单:

    public Object fix(HttpServletRequest request,Map<String, Class<?>> whiteList ,org.apache.log4j.Logger logger) {
        Object obj = null;
        try {
            String className = request.getParameter("className");
            if(null==className){
                //handle error
            }
            if (whiteList.containsKey(className)) {                 //白名单
                obj = whiteList.get(className).newInstance();
            }
        } catch (InstantiationException e) {
            //do something
        }
        return obj;
    }
    

    SQL注入

    正解编码方法:

    应使用参数化查询

    a、参数化查询方法:

    jdbc

    应使用PreparedStatement:

    HttpServletRequest request = ...;
    String userName = request.getParameter("name");
    if(null==userName){
        //handle error
    }
    Connection con = ...
    String query = "SELECT * FROM Users where user=?";
    PreparedStatement pre=conn.prepareStatement(query);
    pre.setString(1, userName);
    pre.execute();
    

    mybatis

    应使用”#”的写法:

    <select id="getByPage" resultType="com.domain.Users" parameterType="com.Param">
    	SELECT 
    		username,id
    	FROM tb_users 
    	WHERE isdeleted=1 
    	<if test="name!=null and name!=''">
        	AND nickname LIKE CONCAT('%', #{name}, '%')
    	</if>
    	ORDER BY 
    		createtime DESC
    	limit #{fromIndex},#{count}
    </select>
    

    注意:

    不论项目是否使用了框架,用户参数需要用到表名、字段名或涉及到order by、group by、limit操作时,参数化查询会使表名、字段名失去原有的意义

    1. 使用java 安全SDK中的方法
        String columnName = request.getParameter("columnName");
        if(null==columnName){
            //handle error
        }
        String columnNameEncode = sqlTool.mysqlSanitise(columnName, true);
        query = "SELECT NAME FROM users order by " + columnNameEncode ;
    
    1. 使用白名单处理:
    switch (columnName){
        case "name":columnName="name";
            break;
        case "num":columnName="num";
            break;
        default:columnName="id";  
    }
    

    Mongo注入

    正解编码方法:

    不可以直接拼接参数,使用BasicDBObject

    String name = request.getParameter(”name");
    if(null==name){
        //handle error
    }
    BasicDBObject databaseQuery = new BasicDBObject("name", name);
    DBCursor cursor = characters.find(databaseQuery);
    try {
        while(cursor.hasNext()) {
            System.out.println(cursor.next());
        }
    } finally {
        cursor.close();
    }
    

    XXE

    正解编码方法:

    1. 在解析XML数据时应限制DTDs(doctypes)参数的解析:
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    try {
          String FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
          dbf.setFeature(FEATURE, true);
    }catch (Exception e) {
          // This should catch a failed setFeature feature
    }
    

    Xpath注入

    正解编码方法:

    应使用Xpath参数化的查询:

    DocumentBuilderFactory builderFactory=DocumentBuilderFactory.newInstance();
    builderFactory.setNamespaceAware(true);
    DocumentBuilder builder=builderFactory.newDocumentBuilder();
    Document document =builder.parse(new File(filepath));
    XPathFactory factory=XPathFactory.newInstance();
    XPath path=factory.newXPath();
    String statement="/user[loginID/text()=$username and password/text()=$password]/text()"; //$username和$password占位 
    SimpleVariableResolver variableResolver = new SimpleVariableResolver();
    variableResolver.addVariable(new QName("password"), password);          //参数绑定
    variableResolver.addVariable(new QName("username"), username);          //参数绑定
    path.setXPathVariableResolver(variableResolver);
    XPathExpression xPathExpression = path.compile(statement);
    

    XSS

    正解编码方法:

    应编码后输出,输出到前端不同的html标签或属性中时,就采用不同的编码方法,

    1. 使用ESAPI时:
        //参数输出到html实体, <div>..xssinput..</div>
        String safe = ESAPI.encoder().encodeForHTML(xssInput);
    
        //参数输出到html标签的属性, <div attr=.. xssinput..>content</div>
        String safe = ESAPI.encoder().encodeForHTMLAttribute(xssInput);
    
    //参数输出到JavaScript中, <script>x='...xssInput...'</script> 
        String safe = ESAPI.encoder().encodeForJavaScript(xssInput);
    
        //富文本
        ESAPI.validator(). getValidSafeHTML()
    
    1. 使用Spring框架时,可用框架自带的HtmlUtils.htmlEscape编码输出到html实体:
    @RequestMapping("/xsstest")
    public String xssTest(@RequestParam("id") String id, Model model){
      
        id=HtmlUtils.htmlEscape(id);
        model.addAttribute("id",id);
        return "index";
    }
    
    1. 未使用框架时,可使用commons-lang库的StringEscapeUtils.escapeHtml编码输出到html实体:
    <%
       String id=request.getParameter("id");
       out.println(StringEscapeUtils.escapeHtml(id));
    %>
    

    CSRF

    正解编码方法:

    1. web passport认证通过后会在cookie植入csrf_token。此类安全问题前端应从cookie中获取csrf_token,以POST方式提交包含csrf_token值的请求,代码如下:
    function getCookie() {
        var value = "; " + document.cookie;
        var parts = value.split("; csrf_token=");
        if (parts.length == 2) 
            return parts.pop().split(";").shift();
    }
    
    $.ajax({
        type: "post",
        url: "/xxxx",
        data: {csrf_token:getCookie()},
        dataType: "json",
        success: function (data) {
            if (data.ec == 200) {
             //do something
            }
        }
    });
    

    后端应从POST请求体中提取csrf_token参数值,进行校验,代码如下:

    public boolean isCSRFProtectPassed(String session,String csrf_token){
    
        if (null==session || null==csrf_token){
            return false;
        }
        if (session.length()!=32 || csrf_token.length()!=32){
            return false;
        }
        if (csrf_token.equals(getCSRFTokenBySession(session))){
            return true;
        }
        return false;
    }
    

    其中getCSRFTokenBySession方法实现如下:

    public String getCSRFTokenBySession(String session){
            return md5(session);
        }
    

    URL跳转漏洞

    正解编码方法:

    服务端应根据具体的业务需求防止不安全的重定向和跳转:

    1. 如果只希望在当前域跳转,或者跳转后的链接比较少且比较固定,那么应在服务端对参数进行白名单限制,非白名单里面的URL禁止跳转;
    String index=request.getParameter("index");
    if(null==index){
        //handle error
    }
    switch (index){
        case "1": url="https://www.trust1.com";
            break;
        case "2": url="https://rule.trust1.com";
            break;
        default:url="https://www.trust1.com";
    }
    response.sendRedirect(url);
    
    1. 如果因为业务需要,跳转后的链接会经常变化而且比较多,应做个中间跳转页面,提示用户将跳转到其他网站,请用户注意防范钓鱼攻击。

    SSRF

    正解编码方法:

    此类安全问题应在服务器端对请求的URL进行限制:服务器端维护一个资源请求列表的映射关系,服务器端根据客户端提交的请求参数从映射关系中获取实际请求的资源。同时应禁止请求私有地址段及内网域名。

    任意文件遍历

    正解编码方法:

    应使用白名单控制路径:

    String directory=request.getParameter("directory");
    if(null==directory){
        //handle error
    }
    switch (directory){
        case "./image": directory="./image";
            break;
        case "./page": directory="./page";
            break;
        ...
        default:directory="./image";
    }
    while(line = readFile(directory))
    {
        //do something
    }
    

    文件上传

    正解编码方法:

    • 校验上传文件大小
    • 文件类型是否符合要求
    • 不可直接使用参数中的原文件名,要随机生成文件名,并限定后缀
    • 保存到文件服务器中
        private Long FILE_MAX_SIZE = 100L*1024*1024;//100M
        @RequestMapping(value = "/upload", method = POST)
        @ResponseBody
        public String upload(@RequestParam("file") MultipartFile file) {
            if(null == file){
                //handle error
            }
            Long filesize = file.getSize();
            if(FILE_MAX_SIZE<filesize){
                //handle error
                return "error";
            }
    
            String file_name = file.getOriginalFilename();
            String[] parts = file_name.split("\\.");
            String suffix = parts[parts.length - 1];
            switch (suffix){
                case "jpeg":
                    suffix = ".jpeg";
                    break;
                case "jpg":
                    suffix = ".jpg";
                    break;
                case "bmp":
                    suffix = ".bmp";
                    break;
                case "png":
                    suffix = ".png";
                    break;
                default:
                    //handle error
                    return "error";
            }
    
            if(!file.isEmpty()) {
                long now = System.currentTimeMillis();
                File tempFile = new File(now + suffix);
    
                FileUtils.copyInputStreamToFile(file.getInputStream(), tempFile);
                //将tempFile保存到文件服务器中,然后删除tempFile
            }
    
            return "OK";
        }
    

    反序列化漏洞

    正解编码方法:

    1. 此类问题应重载ObjectInputStream类的resolveClass方法,校验待反序列化对象的类名:
    public final class SecureObjectInputStream extends ObjectInputStream{
        public SecureObjectInputStream() throws IOException{
            super();
        }
        public SecureObjectInputStream(InputStream in) throws IOException{
            super(in);
        }
        protected Class<?> resolveClass(ObjectStreamClass desc) throws ClassNotFoundException, IOException{
            if (!desc.getName().equals("java_security.Person")) {
                throw new ClassNotFoundException(desc.getName()+" not found"); 
            }
            return super.resolveClass(desc);
        }
    }
    
    1. fastjson和jackson也存在反序列化的问题,应使用如下版本:
    • fastjson,1.2.46及以上版本
    • jackson,2.9.8及以上版本

    WebSocket劫持

    正解编码方法:

    服务端应校验Origin头。

    1. 继承ServerEndpointConfig.Configurator并重写checkOrigin方法:
    public class CustomConfigurator extends ServerEndpointConfig.Configurator {
    	
    	private static final String ORIGIN = "https://www.trust1.com";  
    
        @Override
        public boolean checkOrigin(String originHeaderValue) {
            
        	if(null==originHeaderValue || originHeaderValue.trim().length()==0)
        		return false;
        	return ORIGIN.equals(originHeaderValue);
        }
    }
    

    或者白名单为列表时:

    private static final List<String> ORIGIN_LIST = Arrays.asList(“http://m.trust1.com”,“http://test-s.trust1.com”,“https://s.trust1.com”);
    if(!ORIGIN_LIST.contains(req.headers().get(“Origin”))) {
        return false
    }
    
    1. 使用自定义的配置:
    @ServerEndpoint(value="/echo",configurator = CustomConfigurator.class)
    public class EchoEndpoint {
        //do something
    }
    

    逻辑漏洞

    入参判断

    正解编码方法:

    1. 入参判正负,金额、数量等相关
    if(request.getCoupons() <= 0){
      throw new Exception();
      }
    
    1. 入参取值范围
    • 礼物id、抽奖类型、年龄、手机号等
    • 及时下线过期活动类型、礼物id
    long expireTime = getExpireTime(productId);
    Boolean isExpire = checkExpire(expireTime);
    
    1. 入参组合判断,例如a类型活动应该得到礼物1,而不能获取b类型活动的礼物2
    String type = request.getType();
    String productId = request.getProductId();
    if(null==type || null==productId){
        //handle error
    }
    
    if('a'.equals(type){
      if(!'1'.equals(productId)){
            throw new Exception();
        }
    } else if('b'.equals(type){ 
        if(!'2'.equals(productId)){
            throw new Exception();
        }
    } else
    {
        //handle error
    }
    
    1. 签名验签,入参中加入sign标志验证请求来源,同时防止请求参数被篡改
    public static String checkSign(String appId, Object... args) {
        //线下约定appId
        String appSecret = getAppsecret(appId);
        if(null==appSecret){
            //handle error
        }
        return DigestUtils.sha256Hex(appSecret + “|” + Joiner.on("|").join(args));
    }
    
    1. 三方支付漏洞,例如:限量的优惠购买的,保证只生成一次定单
    //1、加锁
    Lock(id+productId);
    try {
        lock.acquire();
        //2、判断是否已有定单
        if(Exist(id+productId))){
            //3、如果定单成功,返回已购买过;如果定单失败,返回请支付
            …
        }
        return response;
    } finally
        lock.release();
    }
    

    或者在三方支付的回调中判断(建议采用前一种方法)

    //1、加锁
    Lock(id+productId);
    try {
        lock.acquire();
        //2、判断是否已支付
        if(Payed(id+productId)){
            //3、如果购买过且支付成功,退款
            …
        }
        return response;
    } finally
        lock.release();
    }
    

    整数溢出

    正解编码方法:

    1. 类型转换应校验数据类型及数据范围:
    public static boolean isValid(String str) {
        if(null==str){
            return false;
        }
        if (str.length() > 8 || str.length() <= 0) {
            return false;
        }
        char[] chars = str.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            if (!Character.isDigit(chars[i])) {
                return false;
            }        
        }
        return true;
    }
    
    1. 若涉及到交易数据,还应考虑数据的实际意义,如订单数、支付金额等为正数,涉及到的数值计算, 应使用减、除取代加、乘:
    public static boolean checkValue(int number,int increase) {
        final int total=100000;
        if(number<0 || increase<0 || number>total-increase){
            return false;
        }      
        return true;
    }
    
    1. 加法和乘法,也可使用jdk中的java.lang.Math方法,Math.addExact和Math.multiplyExact,这两个函数在溢出时会抛出异常
        try {
            int ret = Math.addExact(number, increase);
            if(ret > total){
                return false;
            }
            return true;
        }catch (Exception e){
            return false;
        }
    
    1. 在使用常数时,注意L的位置
    aa = 2147483647*1000*100L;//有溢出
    aa = 2147483647L*1000*100;//无溢出
    

    资源未释放

    正解编码方法:

    此类安全问题应保证任一执行路径释放资源:

    try {
         Statement stmt = conn.createStatement();
         ResultSet rs=stmt.executeQuery(sqlBase);     
         //do something         
    } catch (Exception e) {
         //do something
    }
    finally{
         stmt.close();
    }
    

    越权

    正解编码方法:

    应判断数据归属:

    @RequestMapping(value="/delete/{addrId}")
    public Object remove(@PathVariable Long addrId){        
        Map<String, Object> respMap = new HashMap<String, Object>();
        if (WebUtils.isLogged()) {
           this.addressService.removeUserAddress(addrId,WebUtils.getLoggedUserId());          //关联用户身份
           respMap.put(Constants.RESP_STATUS_CODE_KEY, Constants.RESP_STATUS_CODE_SUCCESS);
           respMap.put(Constants.MESSAGE,"地址删除成功!");
        }
    

    并发问题

    正解编码方法:

    1. 使用mysql事务,使用事务的前提下,应使用悲观锁或乐观锁解决:

    悲观锁: 在事务中使用select for update加悲观锁,保证总是获取最新的数据

        String sql_select="select num from oversold where id=1 for update";
        String sql_update="update oversold set num=? where id =1";
        conn.setAutoCommit(false);
        try {
            PreparedStatement pre_select=conn.prepareStatement(sql_select);
            PreparedStatement pre_update=conn.prepareStatement(sql_update);
            ResultSet res=pre_select.executeQuery();
            if (res.next()) {
                int num=Integer.parseInt(res.getString(1));
                num--;
                if(num>0){
                    //do something
                    pre_update.setInt(1, num);
                    pre_update.executeUpdate();
                }
            }
            conn.commit();
        } catch (Exception e) {
            conn.rollback();
        }
    

    乐观锁: 需要使用一个新的字段version保存版本号:

        String sql_select="select num,version from oversold where id=1";
        String sql_update="update oversold set num=num-1,version=version+1 where id =1 and version=?";
        conn.setAutoCommit(false);
        try {
            PreparedStatement pre_select=conn.prepareStatement(sql_select);
            PreparedStatement pre_update=conn.prepareStatement(sql_update);
            ResultSet res=pre_select.executeQuery();
            if (res.next()) {
                int num=Integer.parseInt(res.getString("num"));
                int version=Integer.parseInt(res.getString("version"));
                TimeUnit.SECONDS.sleep(10);
                if(num>0){
                    //do something
                    pre_update.setInt(1, version);
                    int ret = pre_update.executeUpdate();
                    if(ret <= 0){
                        //update失败,此时version可能已过期
                    }
                }
            }
            conn.commit();
        } catch (Exception e) {
            conn.rollback();
        }
    

    悲观锁会带来比较大的性能开销,而乐观锁会读取到脏数据,具体采用哪种加锁方式可根据具体业务场景确定。

    1. 通过redis加锁,目前公司redis版本均升级到2.6.12以上,所以使用set代替inc(setnx)/expire,同样也是保证原子性
    jedis.set(String key, String value, String nxxx, String expx, int time)
    
    1. 使用分布式锁(例如:使用InterProcessMutex)
    DistributedLock lock = new DistributedLock(“****”, id;
    try {
            lock.acquire();
            //比较:判断是否已经支付、领取等
            //修改:支付、修改领取数量
            return response;
        } finally {
            lock.release();
        }
    

    敏感信息

    正解编码方法:

    应配置web.xml文件对异常全局处理:

    <error-page>
        <error-code>404</error-code>
        <location>/error.jsp</location> 
        <error-code>500</error-code>
        <location>/error.jsp</location> 
    </error-page>
    

    前端敏感信息:

    1)应在代码上线之前删除注释信息(特别是js脚本、html页面中的敏感信息,账号密码、手机号、特殊链接等等)

    2)web接口返回给前端的参数,如有敏感信息,应打码处理或加密,如下所示:

        1、身份证
            1****************4
        2、手机号
            13*******34
        3、姓名(注意所有接口保持一致,不要有的接口返回是姓*,有的接口返回是*名,这样还是会导致信息泄漏)
            姓*
        4、地理位置
            小数点后三位,(39.910, 116.397)
        5、IP
            不要返回ip
    

    如需加密:

    • 业务需要展现时:参数内容用aes-256加密
    • 不需要展现:参数内容用hash算法sha-256
    展开全文
  • 【安全开发】java安全编码规范

    千次阅读 多人点赞 2018-11-30 15:44:00
    原文转载自:https://github.com/SecurityPaper/SecurityPaper-web/blob/master/_posts/2.SDL%E8%A7%84%E8%8C%83%E6%96%87%E6%A1%A3/2018-08-17-SDL-3-java%E5%AE%89%E5%85%A8%E7%BC%96%E7%A0%81%E8%A7%84...

    申明:本文非笔者原创,原文转载自:https://github.com/SecurityPaper/SecurityPaper-web/blob/master/_posts/2.SDL%E8%A7%84%E8%8C%83%E6%96%87%E6%A1%A3/2018-08-17-SDL-3-java%E5%AE%89%E5%85%A8%E7%BC%96%E7%A0%81%E8%A7%84%E8%8C%83.md

     

    1输入验证和数据合法性校验

    程序接受数据可能来源于未经验证的用户,网络连接和其他不受信任的来源,如果未对程序接受数据进行校验,则可能会引发安全问题。

    1.1避免SQL注入

    使用PreparedStatement预编译SQL,解决SQL注入问题,传递给PreparedStatement对象的参数可以被强制进行类型转换,确保在插入或查询数据时与底层的数据库格式匹配。 

    String sqlString = "select * from db_user where username=? and password=?";
    PreparedStatement stmt = connection.prepareStatement(sqlString);
    stmt.setString(1, username);
    stmt.setString(2, pwd);
    ResultSet rs = stmt.executeQuery();

    1.2避免XML注入

    通过StringBulider 或 StringBuffer 拼接XML文件时,需对输入数据进行合法性校验。 对数量quantity 进行合法性校验,控制只能传入0-9的数字:

    if (!Pattern.matches("[0-9]+", quantity)) {
        // Format violation
      }
      String xmlString = "<item>\n<description>Widget</description>\n" +
                         "<price>500</price>\n" +
                         "<quantity>" + quantity + "</quantity></item>";
      outStream.write(xmlString.getBytes());
      outStream.flush();

    1.3避免跨站点脚本(XSS)

    对产生跨站的参数进行严格过滤,禁止传入<SCRIPT>标签

    //定义需过滤的字段串<script>

    String s = "\uFE64" + "script" + "\uFE65";

    // 过滤字符串标准化

    s = Normalizer.normalize(s, Form.NFKC);

    // 使用正则表达式匹配inputStr是否存在<script>

    Pattern pattern = Pattern.compile(inputStr);
    Matcher matcher = pattern.matcher(s);
    if (matcher.find()) {
      // Found black listed tag
      throw new IllegalStateException();
    } else {
      // ...
    }

    2声明和初始化

    2.1避免类初始化的相互依赖

    例:

    错误的写法:

    public class Cycle {
      private final int balance;
      private static final Cycle c = new Cycle();
      private static final int deposit = (int) (Math.random() * 100); // Random deposit
      public Cycle() {
        balance = deposit - 10; // Subtract processing fee
      }
      public static void main(String[] args) {
        System.out.println("The account balance is: " + c.balance);
      }
    }

    类加载时初始化指向Cycle类的静态变量c,而类Cycle的无参构造方法又依赖静态变量deposit,导致无法预期的结果。 正确的写法:

    public class Cycle {
      private final int balance;
      private static final int deposit = (int) (Math.random() * 100); // Random deposit
      private static final Cycle c = new Cycle();  // Inserted after initialization of required fields
      public Cycle() {
        balance = deposit - 10; // Subtract processing fee
      }
     
      public static void main(String[] args) {
        System.out.println("The account balance is: " + c.balance);
      }
    }

    3表达式

    3.1不可忽略方法的返回值

    忽略方法的放回值可能会导致无法预料的结果。

    错误的写法:

    public void deleteFile(){
      File someFile = new File("someFileName.txt");
       someFile.delete();
    }

    正确的写法:

    public void deleteFile(){
      File someFile = new File("someFileName.txt");
       if (!someFile.delete()) {
        // handle failure to delete the file
      }
    }

    3.2不要引用空指针

    当一个变量指向一个NULL值,使用这个变量的时候又没有检查,这时会导致。NullPointerException。

    在使用变量前一定要做是否为NULL值的校验。

    3.3使用Arrays.equals()来比较数组的内容

    数组没有覆盖的Object. equals()方法,调用Object. equals()方法实际上是比较数组的引用,而不是他们的内容。程序必须使用两个参数Arrays.equals()方法来比较两个数组的内容

    public void arrayEqualsExample() {
      int[] arr1 = new int[20]; // initialized to 0
      int[] arr2 = new int[20]; // initialized to 0
      Arrays.equals(arr1, arr2); // true
    }

    4数字类型和操作

    4.1防止整数溢出

    使用java.lang.Number. BigInteger类进行整数运算,防止整数溢出。

    public class BigIntegerUtil {
    
        private static final BigInteger bigMaxInt = BigInteger.valueOf(Integer.MAX_VALUE);
        private static final BigInteger bigMinInt = BigInteger.valueOf(Integer.MIN_VALUE);
    
        public static BigInteger intRangeCheck(BigInteger val) throws ArithmeticException {
            if (val.compareTo(bigMaxInt) == 1 || val.compareTo(bigMinInt) == -1) {
                throw new ArithmeticException("Integer overflow");
            }
            return val;
        }
    
        public static int addInt(int v1, int v2) throws ArithmeticException {
            BigInteger b1 = BigInteger.valueOf(v1);
            BigInteger b2 = BigInteger.valueOf(v2);
            BigInteger res = intRangeCheck(b1.add(b2));
            return res.intValue(); 
        }
        
        public static int subInt(int v1, int v2) throws ArithmeticException {
            BigInteger b1 = BigInteger.valueOf(v1);
            BigInteger b2 = BigInteger.valueOf(v2);
            BigInteger res = intRangeCheck(b1.subtract(b2));
            return res.intValue(); 
        }
        
        public static int multiplyInt(int v1, int v2) throws ArithmeticException {
            BigInteger b1 = BigInteger.valueOf(v1);
            BigInteger b2 = BigInteger.valueOf(v2);
            BigInteger res = intRangeCheck(b1.multiply(b2));
            return res.intValue(); 
        }
        
        public static int divideInt(int v1, int v2) throws ArithmeticException {
            BigInteger b1 = BigInteger.valueOf(v1);
            BigInteger b2 = BigInteger.valueOf(v2);
            BigInteger res = intRangeCheck(b1.divide(b2));
            return res.intValue(); 
        }
    }

    4.2避免除法和取模运算分母为零

    要避免因为分母为零而导致除法和取模运算出现异常。

    if (num2 == 0) {
      // handle error
    } else {
     result1= num1 /num2;
      result2= num1 % num2;
    }

    5类和方法操作

    5.1数据成员声明为私有,提供可访问的包装方法

    攻击者可以用意想不到的方式操纵public或protected的数据成员,所以需要将数据成员为private,对外提供可控的包装方法访问数据成员。

    5.2敏感类不允许复制

    包含私人的,机密或其他敏感数据的类是不允许被复制的,解决的方法有两种:

    1、类声明为final

    final class SensitiveClass {
      // ...
    }

    2、Clone 方法抛出CloneNotSupportedException异常

    class SensitiveClass {
      // ...
      public final SensitiveClass clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
      }
    }

    5.3比较类的正确做法

    如果由同一个类装载器装载,它们具有相同的完全限定名称,则它们是两个相同的类。 不正确写法:

    // Determine whether object auth has required/expected class object
     if (auth.getClass().getName().equals(
          "com.application.auth.DefaultAuthenticationHandler")) {
       // ...
    }
    正确写法:
    // Determine whether object auth has required/expected class name
     if (auth.getClass() == com.application.auth.DefaultAuthenticationHandler.class) {
       // ...
    }

    5.4不要硬编码敏感信息

    硬编码的敏感信息,如密码,服务器IP地址和加密密钥,可能会泄露给攻击者。

    敏感信息均必须存在在配置文件或数据库中。

    5.5验证方法参数

    验证方法的参数,可确保操作方法的参数产生有效的结果。不验证方法的参数可能会导致不正确的计算,运行时异常,违反类的不变量,对象的状态不一致。 对于跨信任边界接收参数的方法,必须进行参数合法性校验

    private Object myState = null;
    //对于修改myState 方法的入参,进行非空和合法性校验
    void setState(Object state) {
      if (state == null) {
        // Handle null state
      }
      if (isInvalidState(state)) {
        // Handle invalid state
      }
      myState = state;
    }

    5.6不要使用过时、陈旧或低效的方法

    在程序代码中使用过时的、陈旧的或低效的类或方法可能会导致错误的行为。

    5.7数组引用问题

    某个方法返回一个对敏感对象的内部数组的引用,假定该方法的调用程序不改变这些对象。即使数组对象本身是不可改变的,也可以在数组对象以外操作数组的内容,这种操作将反映在返回该数组的对象中。如果该方法返回可改变的对象,外部实体可以改变在那个类中声明的 public 变量,这种改变将反映在实际对象中。

    不正确的写法:

    public class XXX {
    	private String[] xxxx;
    	public String[] getXXX() {
    			return xxxx;
    	}
    }

    正确的写法:

    public class XXX {
    	private String[] xxxx;
    	public String[] getXXX() {
    			String temp[] = Arrays.copyof(…);  // 或其他数组复制方法
    			return temp;
    	}
    }

    5.8不要产生内存泄露

    垃圾收集器只收集不可达的对象,因此,存在未使用的可到达的对象,仍然表示内存管理不善。过度的内存泄漏可能会导致内存耗尽,拒绝服务(DoS)。


    6异常处理

    6.1不要忽略捕获的异常

    对于捕获的异常要进行相应的处理,不能忽略已捕获的异常

    不正确写法:

    class Foo implements Runnable {
      public void run() {
        try {
          Thread.sleep(1000);
        } catch (InterruptedException e) {
          // 此处InterruptedException被忽略
        }
      }
    }

    正确写法:

    class Foo implements Runnable {
      public void run() {
        try {
          Thread.sleep(1000);
        } catch (InterruptedException e) {
          Thread.currentThread().interrupt(); // Reset interrupted status
        }
      }
    }

    6.2不允许暴露异常的敏感信息

    没有过滤敏感信息的异常堆栈往往会导致信息泄漏,

    不正确的写法:

    try {
      FileInputStream fis =
          new FileInputStream(System.getenv("APPDATA") + args[0]);
    } catch (FileNotFoundException e) {
      // Log the exception
      throw new IOException("Unable to retrieve file", e);
    }

    正确的写法:

    class ExceptionExample {
      public static void main(String[] args) {
        File file = null;
        try {
          file = new File(System.getenv("APPDATA") +
                 args[0]).getCanonicalFile();
          if (!file.getPath().startsWith("c:\\homepath")) {
            log.error("Invalid file");
            return;
          }
        } catch (IOException x) {
         log.error("Invalid file");
          return;
        }
        try {
          FileInputStream fis = new FileInputStream(file);
        } catch (FileNotFoundException x) {
          log.error("Invalid file");
          return;
        }
      }
    }

    6.3不允许抛出RuntimeException, Exception,Throwable

    不正确的写法:

    boolean isCapitalized(String s) {
      if (s == null) {
        throw new RuntimeException("Null String");
      }
    }
    
    private void doSomething() throws Exception {
      //...
    }

    正确写法:

    boolean isCapitalized(String s) {
      if (s == null) {
        throw new NullPointerException();
      }
    }
    
    private void doSomething() throws IOException {
      //...
    }

    6.4不要捕获NullPointerException或其他父类异常

    不正确的写法:

    boolean isName(String s) {
      try {
        String names[] = s.split(" ");
        if (names.length != 2) {
          return false;
        }
        return (isCapitalized(names[0]) && isCapitalized(names[1]));
      } catch (NullPointerException e) {
        return false;
      }
    }

    正确的写法:

    boolean isName(String s) /* throws NullPointerException */ {
      String names[] = s.split(" ");
      if (names.length != 2) {
        return false;
      }
      return (isCapitalized(names[0]) && isCapitalized(names[1]));
    }

    7多线程编程

    7.1确保共享变量的可见性

    对于共享变量,要确保一个线程对它的改动对其他线程是可见的。 线程可能会看到一个陈旧的共享变量的值。为了共享变量是最新的,可以将变量声明为volatile或同步读取和写入操作。 将共享变量声明为volatile

    final class ControlledStop implements Runnable {
      private volatile boolean done = false;
      @Override public void run() {
        while (!done) {
          try {
            // ...
            Thread.currentThread().sleep(1000); // Do something
          } catch(InterruptedException ie) { 
            Thread.currentThread().interrupt(); // Reset interrupted status
          } 
        }    
      }
      public void shutdown() {
        done = true;
      }
    }

    同步读取和写入操作:

    final class ControlledStop implements Runnable {
      private boolean done = false;
      @Override public void run() {
        while (!isDone()) {
          try {
            // ...
            Thread.currentThread().sleep(1000); // Do something
          } catch(InterruptedException ie) { 
            Thread.currentThread().interrupt(); // Reset interrupted status
          } 
        }    
      }
      public synchronized boolean isDone() {
        return done;
      }
      public synchronized void shutdown() {
        done = true;
      }
    }

    7.2确保共享变量的操作是原子的

    除了要确保共享变量的更新对其他线程可见的,还需要确保对共享变量的操作是原子的,这时将共享变量声明为volatile往往是不够的。需要使用同步机制或Lock 同步读取和写入操作:

    final class Flag {
      private volatile boolean flag = true;
      public synchronized void toggle() {
        flag ^= true; // Same as flag = !flag;
      }
      public boolean getFlag() {
        return flag;
      }
    }

    //使用读取锁确保读取和写入操作的原子性

    final class Flag {
      private boolean flag = true;
      private final ReadWriteLock lock = new ReentrantReadWriteLock();
      private final Lock readLock = lock.readLock();
      private final Lock writeLock = lock.writeLock();
      public void toggle() {
        writeLock.lock();
        try {
          flag ^= true; // Same as flag = !flag;
        } finally {
          writeLock.unlock();
        }
      }
      public boolean getFlag() {
        readLock.lock();
        try {
          return flag;
        } finally {
          readLock.unlock();
        }
      }
    }

    7.3不要调用Thread.run(),不要使用Thread.stop()以终止线程

    7.4确保执行阻塞操作的线程可以终止

      public final class SocketReader implements Runnable {
      private final SocketChannel sc;
      private final Object lock = new Object();
      public SocketReader(String host, int port) throws IOException {
        sc = SocketChannel.open(new InetSocketAddress(host, port));
      }
      @Override public void run() {
        ByteBuffer buf = ByteBuffer.allocate(1024);
        try {
          synchronized (lock) {
            while (!Thread.interrupted()) {
              sc.read(buf);
              // ...
            }
          }
        } catch (IOException ie) {
          // Forward to handler
        }
      }
      public static void main(String[] args) 
                              throws IOException, InterruptedException {
        SocketReader reader = new SocketReader("somehost", 25);
        Thread thread = new Thread(reader);
        thread.start();
        Thread.sleep(1000);
        thread.interrupt();
      }
    }

    7.5相互依存的任务不要在一个有限的线程池执行

    有限线程池指定可以同时执行在线程池中的线程数量的上限。程序不得使用有限线程池线程执行相互依赖的任务。可能会导致线程饥饿死锁,所有的线程池执行的任务正在等待一个可用的线程中执行一个内部队列阻塞


    8输入输出

    8.1程序终止前删除临时文件

    8.2检测和处理文件相关的错误

    Java的文件操作方法往往有一个返回值,而不是抛出一个异常,表示失败。因此,忽略返回值文件操作的程序,往往无法检测到这些操作是否失败。Java程序必须检查执行文件I / O方法的返回值。

    不正确的写法:

    File file = new File(args[0]);
    file.delete();
    正确的写法:
    File file = new File("file");
    if (!file.delete()) {
      log.error("Deletion failed");
    }

    8.3及时释放资源

    垃圾收集器无法释放非内存资源,如打开的文件描述符与数据库的连接。因此,不释放资源,可能导致资源耗尽攻击。

    try {
      final FileInputStream stream = new FileInputStream(fileName);
      try {
        final BufferedReader bufRead =
            new BufferedReader(new InputStreamReader(stream));
     
        String line;
        while ((line = bufRead.readLine()) != null) {
          sendLine(line);
        }
      } finally {
        if (stream != null) {
          try {
            stream.close();
          } catch (IOException e) {
            // forward to handler
          }
        }
      }
    } catch (IOException e) {
      // forward to handler
    }

    9序列化

    9.1不要序列化未加密的敏感数据

    序列化允许一个对象的状态被保存为一个字节序列,然后重新在稍后的时间恢复,它没有提供任何机制来保护序列化的数据。敏感的数据不应该被序列化的例子包括加密密钥,数字证书。 解决方法:

    1. 对于数据成员可以使用transient ,声明该数据成员是瞬态的。
    2. 重写序列化相关方法writeObject、readObject、readObjectNoData,防止被子类恶意重写
    class SensitiveClass extends Number {
      // ...
      protected final Object writeObject(java.io.ObjectOutputStream out) throws NotSerializableException {
        throw new NotSerializableException();
      }
      protected final Object readObject(java.io.ObjectInputStream in) throws NotSerializableException {
        throw new NotSerializableException();
      }
      protected final Object readObjectNoData(java.io.ObjectInputStream in) throws NotSerializableException {
        throw new NotSerializableException();
      }
    }

    9.2在序列化过程中避免内存和资源泄漏

    不正确的写法:

    class SensorData implements Serializable {
      // 1 MB of data per instance!
       public static SensorData readSensorData() {...}
      public static boolean isAvailable() {...}
    }
    class SerializeSensorData {
      public static void main(String[] args) throws IOException {
        ObjectOutputStream out = null;
        try {
          out = new ObjectOutputStream(
              new BufferedOutputStream(new FileOutputStream("ser.dat")));
          while (SensorData.isAvailable()) {
            // note that each SensorData object is 1 MB in size
            SensorData sd = SensorData.readSensorData();
            out.writeObject(sd);
          }
        } finally {
          if (out != null) {
            out.close();
          }
        }
      }
    }

    正确写法:

    class SerializeSensorData {
      public static void main(String[] args) throws IOException {
        ObjectOutputStream out = null;
        try {
          out = new ObjectOutputStream(
              new BufferedOutputStream(new FileOutputStream("ser.dat")));
          while (SensorData.isAvailable()) {
            // note that each SensorData object is 1 MB in size
            SensorData sd = SensorData.readSensorData();
            out.writeObject(sd);
            out.reset(); // reset the stream
          }
        } finally {
          if (out != null) {
            out.close();
          }
        }
      }
    }

    9.3反序列化要在程序最小权限的安全环境中

    (完成)

    展开全文
  • CERT关于Java安全编码规范的新书

    千次阅读 2013-09-20 23:30:20
    CERT关于Java安全编码规范的新书:Java Coding Guidelines: 75 Recommendations for Reliable and Secure Programshttp://...

    CERT关于Java安全编码规范的新书:

    Java Coding Guidelines: 75 Recommendations for Reliable and Secure Programs

    http://www.informit.com/store/java-coding-guidelines-75-recommendations-for-reliable-9780321933157

     

    展开全文
  • Java编码规范

    热门讨论 2014-02-20 17:27:40
    同时,编码规范还可以提高程序代码的安全性和可维护性,提高软件开发的生产效率,所以,编码规范对于程序员而言至关重要。 为使开发项目中所有的JAVA程序代码的风格保持一致,增加代码的可读性,便于维护及内部交流...
  • Java 编码规范11(安全规约)

    千次阅读 2018-04-08 00:07:51
    Java 编码规范1(编程规约-命名风格) Java 编码规范2(编程规约-常量定义) Java 编码规范3(编程规约-代码格式) Java 编码规范4(编程规约-OOP规约) Java 编码规范5(编程规约-集合处理) Java 编码规范6(编程规约-...
  • Java代码编码规范(1)

    千次阅读 2015-09-17 17:16:36
    Java代码编码规范 第一部分:Convention(编码约定)1.右括号放在一行的开始 Noncompliant Code Example if(condition) { doSomething();} Compliant Solution if(condition) { doSomething(); } 2.抽象...
  • java安全编码指南之:Number操作

    万次阅读 2020-09-10 09:55:41
    java中可以被称为Number的有byte,short,int,long,float,double和char,我们在使用这些Nubmer的过程中,需要注意些什么内容呢?一起来看看吧。 Number的范围 每种Number类型都有它的范围,我们看下java中Number...
  • java程序是跨平台的,可以运行在windows也可以运行在linux。但是平台不同,平台中的文件权限也是不同的。...本文主要讲讲linux下面的文件的权限和安全性问题,并且探讨一下如何在java程序中考虑文件的安全性。
  • java安全编码指南之:序列化Serialization

    万次阅读 热门讨论 2020-11-01 10:27:26
    序列化是java中一个非常常用又会被人忽视的功能,我们将对象写入文件需要序列化,同时,对象如果想要在网络上传输也需要进行序列化。 序列化的目的就是保证对象可以正确的传输,那么我们在序列化的过程中需要注意些...
  • Java Web安全编码

    2020-02-17 23:35:46
    JAVA Web安全编码规范要求 Java Web安全编码 输入与输出数据验证 身份认证和访问控制
  • Java 编码规范1(编程规约-命名风格) Java 编码规范2(编程规约-常量定义) Java 编码规范3(编程规约-代码格式) Java 编码规范4(编程规约-OOP规约) Java 编码规范5(编程规约-集合处理) Java 编码规范6(编程规约-...
  • java安全编码指南之:Mutability可变性

    万次阅读 2020-09-03 09:20:15
    mutable(可变)和immutable(不可变)对象是我们在java程序编写的过程中经常会使用到的。 可变类型对象就是说,对象在创建之后,其内部的数据可能会被修改。所以它的安全性没有保证。 而不可变类型对象就是说,对象...
  • 标准的Java编码规范手册

    万次阅读 多人点赞 2016-05-10 17:21:53
    今天分享一个标准的Java编码规范给大家,希望对于大家今后的开发工作带来帮助。编码规范的意义  在项目开发维护中,编码规范作为开发规范的一个组成部分,是十分重要和必须的,它不仅仅是为了提高开发效率,也有利...
  • java安全编码指南之:线程安全规则

    万次阅读 热门讨论 2020-10-23 09:26:22
    如果我们在多线程中引入了共享变量,那么我们就需要考虑一下多线程下线程安全的问题了。那么我们在编写代码的过程中,需要注意哪些线程安全的问题呢?
  • java安全编码指南之:输入注入injection

    万次阅读 热门讨论 2020-10-12 09:03:44
    注入问题是安全中一个非常常见的问题,今天我们来探讨一下java中的SQL注入和XML注入的防范。
  • Java 编码规范1(编程规约-命名风格) Java 编码规范2(编程规约-常量定义) Java 编码规范3(编程规约-代码格式) Java 编码规范4(编程规约-OOP规约) Java 编码规范5(编程规约-集合处理) Java 编码规范6(编程规约-...
  • java编码规范

    千次阅读 2006-05-16 08:31:00
    Java 编码规范翻译:王士勇(转载请保留作者,谢谢)1. 引言1.1. 为什么要编码规范编码规范为什么是重要的?有以下一些理由:l 一份软件80%的生命周期是维护期l 任何软件都很难说他的整个生命周期都是由他的原始...
  • JAVA-编码规范-代码风格-命名

    千次阅读 2015-09-23 11:10:34
    很多java规范,内容偏向于对排版的要求,对java语言特性使用上的注意事项描述较少,为了能帮助我们合理的使用java语言,规避语言陷阱,特发此专题博客。 代码总体原则: 1:清晰第一。清晰性是易于维护,易于重构的...
  • java语言编码规范(华为)

    千次阅读 2016-10-14 12:05:59
    Table of Contents 目录 1.范围 2.规范性引用文件 3.术语和定义 4.排版规范 ...7.编码规范 7.1.规则 7.2.建议 8.JTEST规范 8.1.规则 8.2.建议     1.范围 本规范规定了使用Java语言编...
  • JAVA编码规范

    千次阅读 2006-12-13 13:11:00
    JAVA 编码标准规范 一、JAVA编码标准规则1. JavaBeans [BEAN]2. 编码约定/ 惯例Coding Conventions [CODSTA]3. 契约设计/ Design by Contract [DBC]4. Enterprise JavaBeans [EJB]5. 异常/ Exceptions [EXCEPT...
  • Java 编码规范1(编程规约-命名风格)

    千次阅读 2018-04-07 01:14:40
    Java 编码规范1(编程规约-命名风格) Java 编码规范2(编程规约-常量定义) Java 编码规范3(编程规约-代码格式) Java 编码规范4(编程规约-OOP规约) Java 编码规范5(编程规约-集合处理) Java 编码规范6(编程规约-...
  • Java 编码规范1(编程规约-命名风格) Java 编码规范2(编程规约-常量定义) Java 编码规范3(编程规约-代码格式) Java 编码规范4(编程规约-OOP规约) Java 编码规范5(编程规约-集合处理) Java 编码规范6(编程规约-...
  • Java 编码规范1(编程规约-命名风格) Java 编码规范2(编程规约-常量定义) Java 编码规范3(编程规约-代码格式) Java 编码规范4(编程规约-OOP规约) Java 编码规范5(编程规约-集合处理) Java 编码规范6(编程规约-...
  • java安全编码指南之:Thread API调用规则

    万次阅读 热门讨论 2020-10-19 09:15:03
    java中多线程的开发中少不了使用Thread,我们在使用Thread中提供的API过程中,应该注意些什么规则呢? 一起来看一看吧。
  • Java 编码规范1(编程规约-命名风格) Java 编码规范2(编程规约-常量定义) Java 编码规范3(编程规约-代码格式) Java 编码规范4(编程规约-OOP规约) Java 编码规范5(编程规约-集合处理) Java 编码规范6(编程规约-...
  • 一、java文件组织 文件组织规则:由于超过2000行的程序难以阅读,应该尽量避免出现超过2000行的程序。一个Java源文件都包含一个单一的公共类或接口。若私有类和接口与一个公共类相关联,可以将它们和公共类放入同一...
  • 华为Java编码规范

    2020-05-29 10:05:00
    >>> 一、java基础语句规范 1.1 switch得default语句 必须带有default语句,除非是枚举类型。 1.2 switch的break语句 分支必须包含break语句,否则不满足条件会发生全部输出语句,不会结束。 1.3 建议 if-else-if类型...
  • OWASP-安全编码规范

    千次阅读 2021-05-31 23:27:48
    OWASP-安全编码规范 原文 pdfhttp//www.owasp.org.cn/owasp-project/download/OWASP_SCP_Quick_Reference_GuideChinese.pdf 1. 序言 本项目与技术无关的文档以清单列表的形式,定义了一套可以集成到软件开发生命周期...
  •  本书不仅从语言角度系统而详 细地阐述Java安全编码的要素、标准、规范和最佳实践,而且从架构设计的角度分析了Java API存在的设计缺陷和可能存 在的安全风险,以及应对的策略和措施。 对其内容详细阅读

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 79,917
精华内容 31,966
关键字:

java安全编码规范

java 订阅