java编程规范每行代码窄字符,wiki/0xFE_编程规范.md at master · islibra/wiki · GitHub

0xFE_编程规范

使用UTF-8编码

使用空格缩进

命名

清晰表达意图, 少用缩写(行业通用除外, 如: request=req, response=resp, message=msg), 不应使用特殊前缀或后缀

用复数形式代表集合

\w{2,64}, 除循环变量i, j, k, 异常e外

类型

命名风格

全小写, 点号分割, 允许数字, 无下划线

类, 接口, 枚举, 注解

名词/形容词, 大驼峰, 缩写也用大驼峰, 测试类加Test后缀

字段, 局部变量, 方法, 方法参数

介词/动词, 小驼峰, 测试方法可有下划线_

静态常量, 枚举

全大写, 下划线分割, 常见的Logger, Lock可除外

泛型

单个大写字母, 可接一个数字

异常

加后缀Exception

数据库

全小写下划线

表名

全大写下划线

列名

全大写下划线

注释

Javadoc用于public/protected

排版

文件非空非注释不超过2000行, 每行120窄字符, 方法不超过50行

换行开始:

.

::

&

|

修饰符

public

abstract, static

final transient volatile synchronized

void

数字后缀大写

long value = 1000000000L

数组声明

String[] args = {"a", "b"}

条件和循环必须使用大括号, 左括号在行尾

变量

一个局部变量只表达一种含义, 避免前后不一致

浮点数不能使用==判等, 不能精确计算, 不能作为循环变量

BigDecimal income = new BigDecimal("1.03");

BigDecimal expense = new BigDecimal("0.42");

// 0.61

LOG.info("BigDecimal: " + income.subtract(expense));

// 0.61

LOG.info("1.03f - 0.42f: " + (1.03f - 0.42f));

方法

包含方法本身, 嵌套深度不超过4

参数不超过5个, 异常不超过5个

类,接口

接口中属性缺省public static final, 方法缺省public abstract

异常

在finally中不要使用return, break, continue

日志

使用SLF4J+LogBack

private static final Logger LOG = LoggerFactory.getLogger(Xxx.class)

日志级别

条件或占位符

不要使用foreach remove, 可以使用iterator.remove()

安全编程

数据校验

在信任边界以内(如Web服务端)进行数据校验

输入校验

输出校验

接收白名单: Pattern.matches("^[0-9a-zA-Z_]+$", "abc_@123")

拒绝黑名单, 白名单净化(对所有非字母数字删除/编码/替换), 黑名单净化(对某些特殊字符删除/编码/替换)

禁止使用assert校验

防止命令注入

Runtime.exec()

java.lang.ProcessBuilder

防止SQL注入

参数化查询PreparedStatement, {==参数下标从1开始==}: stmt.setString(1, userName);

存储过程conn.prepareCall()也不能拼接SQL再执行

Hibernate 原生SQLsession.createSQLQuery()应使用参数化查询, HQLsession.createQuery()应使用基于位置/名称的参数化查询

iBatis禁止使用$拼接SQL

白名单校验(表名/字段名)

转码

文件路径校验前必须先进行标准化

等价路径: 软链接

目录遍历: 路径跨越../

必须使用getCanonicalPath(), 其他方法getPath(), getParent(), getAbsolutePath()均不会归一化

解压

目录遍历

DoS

错误示例

public class IODemo {

private static final Logger log = Logger.getLogger(IODemo.class.getName());

public static void zipIO(String path) {

FileInputStream fin = null;

BufferedInputStream bin = null;

ZipInputStream zin = null;

FileOutputStream fout = null;

BufferedOutputStream bout = null;

try {

File zipFile = new File(path);

// 解压到当前目录

String parent = zipFile.getParent() + File.separator;

fin = new FileInputStream(zipFile);

bin = new BufferedInputStream(fin);

zin = new ZipInputStream(bin);

ZipEntry entry = null;

int count;

final int BUFFER_SIZE = 512;

byte data[] = new byte[BUFFER_SIZE];

// 对压缩包中的每个文件

while ((entry = zin.getNextEntry()) != null) {

// toString()调用了getName()

log.info("Extracting: " + entry);

File unzipFile = new File(parent + entry.getName());

if (unzipFile.isDirectory()) {

// 目录

unzipFile.mkdir();

} else {

final int FILE_MAXSIZE = 0x6400000; // 100MB

// 判断文件大小, 可以被伪造

if (entry.getSize() == -1 || entry.getSize() > FILE_MAXSIZE) {

throw new IllegalArgumentException("File is too big.");

}

fout = new FileOutputStream(unzipFile);

bout = new BufferedOutputStream(fout, BUFFER_SIZE);

while ((count = zin.read(data, 0, BUFFER_SIZE)) != -1) {

bout.write(data, 0, count);

bout.flush();

}

}

zin.closeEntry();

}

} catch (IOException e) {

log.severe(e.getMessage());

} finally {

try {

bout.close();

fout.close();

zin.close();

bin.close();

fin.close();

} catch (IOException e) {

log.severe(e.getMessage());

}

}

}

public static void main(String[] args) {

zipIO("D:\\tmp\\io.zip");

}

}

推荐示例

public class IODemo {

private static final Logger log = Logger.getLogger(IODemo.class.getName());

public static void zipIO(String zipFilepath) {

FileInputStream fin = null;

BufferedInputStream bin = null;

ZipInputStream zin = null;

FileOutputStream fout = null;

BufferedOutputStream bout = null;

try {

File zipFile = new File(zipFilepath);

// 解压到当前目录

String parent = zipFile.getParent() + File.separator;

fin = new FileInputStream(zipFile);

bin = new BufferedInputStream(fin);

zin = new ZipInputStream(bin);

ZipEntry entry = null;

int count;

final int BUFFER_SIZE = 512;

byte data[] = new byte[BUFFER_SIZE];

// 总解压文件数量

final int TOTAL_FILE_NUM = 1000;

// 总解压文件大小, 100MB

final int TOTAL_FILE_MAXSIZE = 0x6400000;

int totalFileNum = 0;

int totalFileSize = 0;

while ((entry = zin.getNextEntry()) != null) {

// 安全编程1: 校验解压文件数量

if (totalFileNum > TOTAL_FILE_NUM) {

throw new IllegalArgumentException("Too many files.");

}

// toString()调用了getName()

log.info("Extracting: " + entry);

File unzipFile = new File(parent + entry.getName());

// 安全编程2: 校验解压文件路径

String unzipFilepath = unzipFile.getCanonicalPath();

if (!unzipFilepath.startsWith(parent)) {

throw new IllegalArgumentException(

"File is outside extraction target directory");

}

if (unzipFile.isDirectory()) {

// 目录

unzipFile.mkdirs();

} else {

File dir = new File(unzipFile.getParent());

if (!dir.exists()) {

dir.mkdirs();

}

fout = new FileOutputStream(unzipFile);

bout = new BufferedOutputStream(fout, BUFFER_SIZE);

while ((count = zin.read(data, 0, BUFFER_SIZE)) != -1) {

// 安全编程3: 校验解压文件总大小

if (totalFileSize > TOTAL_FILE_MAXSIZE) {

throw new IllegalArgumentException("File is too big.");

}

bout.write(data, 0, count);

bout.flush();

totalFileSize += count;

}

}

zin.closeEntry();

totalFileNum++;

}

} catch (IOException e) {

log.severe(e.getMessage());

} finally {

try {

if (bout != null) {

bout.close();

}

if (fout != null) {

fout.close();

}

if (zin != null) {

zin.close();

}

if (bin != null) {

bin.close();

}

if (fin != null) {

fin.close();

}

} catch (IOException e) {

log.severe(e.getMessage());

}

}

}

public static void main(String[] args) {

zipIO("D:\\tmp\\io.zip");

}

}

防止CRLF和敏感信息记录日志

接收白名单

黑名单净化: message = message.replace('\n', '_').replace('\r', '_');

防止拼接格式化字符串造成敏感信息泄露

// 敏感信息: 信用卡失效时间

Calendar expirationDate = Calendar.getInstance();

expirationDate.set(2020, Calendar.FEBRUARY, 20);

// 客户端输入

// String input = "12";

// poc

String input = "Date: %1$tY-%1$tm-%1$te";

if (!String.valueOf(expirationDate.get(Calendar.DAY_OF_MONTH)).equals(input)) {

// 存在格式化字符串注入

System.out.printf(input + " did not match! HINT: It was issued in month "

+ "%1$tm.\n", expirationDate);

// 正确使用

System.out.printf("%s did not match! HINT: It was issued in month "

+ "%2$tm.\n", input, expirationDate);

}

防止异常泄露敏感信息

敏感的异常消息

敏感的异常类型

FileNotFoundException

捕获并抛出IOException

自定义SecurityIOException继承IOException

不抛出异常, 只打印简单日志

白名单

异常名称

信息泄露或威胁描述

java.io.FileNotFoundException

泄露文件系统结构和文件名列举

java.util.jar.JarException

泄露文件系统结构

java.util.MissingResourceException

资源列举

java.security.acl.NotOwnerException

所有人列举

java.util.ConcurrentModificationException

可能提供线程不安全的代码信息

javax.naming.InsufficientResourcesException

服务器资源不足(可能有利于DoS攻击)

java.net.BindException

当不信任客户端能够选择服务器端口时造成开放端口列举

java.lang.OutOfMemoryError

DoS

java.lang.StackOverflowError

DoS

java.sql.SQLException

数据库结构,用户名列举

JSONException

-

防止空指针

调用null的方法, 如obj=null; obj.equals(xxx);, String s=null; s.split(" ");

访问null的属性

获取null数组的长度

访问数组中的null元素

防止除0

除法: /

模: %

多线程

防止锁暴露

同步方法

同步this的代码块

同步public static锁的代码块

正确示例:

public class LockDemo {

private final Object LOCK = new Object();

public void changeValue() {

synchronized (LOCK) {

// ...

}

}

}

锁类型

错误示例:

Boolean只有两个值

基础数据类型的包装类自动装箱

private int count = 0;

private final Integer LOCK = count;

字符串常量: private final String LOCK = "LOCK";

Interned String对象: private final String LOCK = new String("LOCK").intern();, 在常量池中

getClass(): 子类和基类, 类和内部类获取到的对象不同

内置锁

private final Lock LOCK = new ReentrantLock();

public void changeValue() {

synchronized (LOCK) {

// ...

}

}

正确示例:

基础数据类型的包装类

private int count = 0;

private final Integer LOCK = new Integer(count);

字符串实例: private final String LOCK = new String("LOCK");

Object

Base.class/Class.forName("Base"): 明确类名

保护静态数据

错误示例:

// 静态数据

private static volatile int counter;

// 非静态锁对象

private final Object LOCK = new Object();

private static volatile int counter;

public synchronized void run() {

// ...

}

正确示例:

private static volatile int counter;

private static final Object LOCK = new Object();

保证顺序获得和释放多个锁

在finally中释放锁

禁止调用Thread.run()在当前线程中执行run()

禁止调用Thread.stop()导致线程非正常释放锁

通过修改volatile变量终止线程中的循环

调用Thread.interrupt()终止线程中的循环

禁止非线程安全的方法覆写线程安全的方法

IO

使用File.createTempFile创建临时文件, finally删除

使用asReadOnlyBuffer()返回Buffer的只读视图

防止阻塞在外部进程

Runtime rt = Runtime.getRuntime();

Process proc = rt.exec("notepad.exe");

// java.lang.IllegalThreadStateException: process has not exited

int exitVal = proc.exitValue();

Runtime rt = Runtime.getRuntime();

Process proc = rt.exec("notepad.exe");

// 一直阻塞到外部进程终止

int exitVal = proc.waitFor();

使用int保存read()的返回值

序列化

使用transient保护敏感信息

序列化敏感数据时先签名后加密, 防止签名被篡改后正常数据校验不通过

禁止序列化非静态的内部类

如果某敏感操作使用安全管理器检查, 防止反序列化绕过

防止反序列化注入

二进制

xml

XMLDecoder, 无消减措施

XStream, setupDefaultSecurity()或addPermission白名单

json: fastjson, jackson

type白名单

类加载

存在安全管理器检查的方法要声明为private或final, 防止子类复写

自定义类加载器覆写getPermissions()方法时需要调用super.getPermissions()

使用本地KeyStore中的证书校验jar中的签名

加解密

算法javax.crypto

SHA256 + 8Bytes salt + iterator 10000 => 256bit(32Bytes)

AES/GCM/NoPadding

RSA

DSA

ECDSA

禁止

DES

AES ECB

强随机数SecureRandom

javax.net.ssl.SSLSocket

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/561327.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

keil4怎么移植其他人的程序_简单和你聊聊造血干细胞移植!

造血干细胞是个什么“鸟”?造血干细胞,人体血细胞的老祖宗。它的分裂方式也十分独特,由一个细胞分裂为两个细胞时,其中一个细胞会慢慢长大,增殖分化为红细胞、白细胞和血小板等等;另一个细胞仍然保持干细胞…

matlab 信号处理 教程,MATLAB信号处理仿真 实验_教程-学习文件.pdf

MATLAB信号处理仿真实验从观察正弦波开始用绳量给我的地界坐落在佳美之处我的产业实在美好杜伟韬duweitao广播电视数字化教育部工程研究中心2013年 4月23 日于 北京定福庄献给广播学院的核桃林,还有我的老师们目目目录录录0 修修修订订订记记记录录录和和和意意意见…

怎么在电脑上任意截屏_草地上打滚、墙上任意涂鸦,幼儿园让孩子“想怎么玩就怎么玩”...

(图为孩子们开心地在“山坡”上打滚。 学校供图)长江日报-长江网10月26日讯 10月26日,汉阳区玉龙幼儿园的孩子们冲上小山坡滑草,草地上打滚,滚筒里钻来钻去,墙上任意涂鸦,在梯子搭建的木桥上自由行走……孩子们自发地三…

pyaudio usb playback_苹果安卓手机充电器USB接口PSD源文件psd素材

分类:详情页类目:数码家电格式:psd体积:尺寸:790*12168编号:13182638软件: Photoshop CS6(.psd)颜色模式 : RGB图像类型:位图版权:独家版权LOGO/ 实景图/人物/字体/产品 …

mysql 执行sql error 2,Mysql:执行source sql脚本时,出现:error 2

Centos下部署mysql:1、yum -y install mysql*;2、service mysqld start;3、chkconfig mysqld on;4、设置用户名和密码:mysqladmin -uroot password1234565、进入数据库:mysql -uroot -p 回车后,输入设置的密码6、建立数据库:creat…

horizon client 无法识别域_iText for Mac(OCR识别图中文字工具)

itext mac中文特别版是一款从图片中识别文字的OCR(光学字符识别)工具。通过截图、拖拽图片,即可以从扫描版的PDF等任意图片中识字,并且可以很好的解决摘抄和批注需求。而且itext mac版使用腾讯、Google 双引擎,识别效果惊人地准确。iText for…

mysql 操作表的例子,mysql中库和表的简单操作总结(附示例)

本篇文章给大家带来的内容是关于mysql中库和表的简单操作总结(附示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。一. 库的操作1.创建数据库创建数据库:create database 库名 charset utf8; charset uft8 可选项1.2 数据…

.net 5 正式版_iOS14.1正式版和14.2 Beta 4测试版一同发布 附16张内置新壁纸下载

今天凌晨,苹果同时推送了 iOS 14.1 正式版 和 iOS 14.2 Beta 4 测试版 系统更新,对于正式版和开发者用户来说,今天均可以将手中的 iPhone 升级到最新的系统版本。iOS 14.1 正式版更新了什么?先来看下 iOS 14.1 正式版,…

自适应均衡器 matlab程序,基于lms自适应均衡器matlab仿真

基于lms自适应均衡器matlab仿真 毕 业 设 计 (2014 届) 题 目 一种基于 OpenCV 的摄像机标定方 法学 院 物理电气信息学院 专 业 电子信息工程 年 级 2010 学生学号 12010245348 学生姓名 李 鑫 指导教师 车 进 2014 年 5 月 6 日摘要摄像机标定是在机器视觉和工业测量等领域中…

bloomberg用法 固定收益_干货 | 日语高考高频考点:助词を的用法

在日语高考题中,第二大题综合知识运用板块,16-20题固定考察日语的助词的使用。很多同学反映说:高考日语最难学的部分就是助词了。因为中文的结构中是没有助词成分,同时助词的用法也挺多,所以经常容易搞混。日语是黏着语…

php+new+mysqli+utf+8,MySQL和PHP:utf-8带有西里尔字符

HUH函数你在这里混合API,mysql_*和mysqli_*不会混在一起。你应该坚持mysqli_(看起来你无论如何都是),mysql_*函数被弃用,并在PHP 7中完全删除。你的实际问题是某个地方的字符集问题。这里有几个指针,可以帮助您为您的应用程序获得…

arduinojson 转 string_安德胜工作室发来本周五嗨唱转起来第二季首秀的嘉宾剧透...

湖南卫视全民音乐综艺互动秀《嗨唱转起来2》10月2日超燃回归,在金秋十月为观众带来新一季的惊喜。近日,官方微博官宣大玩家阵容:“太阳女神”谢娜、“节奏先生”潘玮柏、“行走的造梗机”大张伟。她是热情女神,点燃全场&#xff0…

php url参数时间戳,AJAX GET 请求 URL 最后面缀的那个类似于时间戳的参数是什么啊?...

Dark1X2019-05-06 10:43:44 08:00ochatokori 感谢我在测试的时候发现爬虫不加这个签名参数也是可以的。现在的问题是浏览器上面获取的的数据与爬虫获取到的数据不一致。你有空的话复现帮我看看呀,麻烦了。浏览器访问: https://删除这几个字 wk588.com/to…

python补充urllib教程,Python爬虫之urllib基础用法教程

综述本系列文档用于对Python爬虫技术进行简单的教程讲解,巩固自己技术知识的同时,万一一不小心又正好对你有用那就更好了。Python 版本是3.7.4urllib库介绍它是 Python 内置的HTTP请求库,也就是说我们不需要额外安装即可使用,它包…

鼬电脑壁纸_火影忍者高清壁纸需要自取1080p

更新了,火影忍者高清壁纸。(图片源于网络,侵权必删)别忘,关注、点赞、收藏哦。需要原图评论点赞,我给你喔。传送门;可爱的橙猪猪:鬼刀高清壁纸,电脑1080p,无水印。​zhuanlan.zhihu.…

二元置信椭圆r语言_r语言二元期权barrier option实现案例

原文链接:http://tecdat.cn/?p4051​tecdat.cnDouble-no-touch(DNT)选项是二元期权,在到期时支付固定金额的现金。我们将展示两种不同的方式来定价包含两种不同定价方法的DNT。​​​首先,我们将尝试使用正常参数&…

win7可以运行的mysql,win7下mysql安装

1、下载mysqlhttps://dev.mysql.com/downloads/mysql/2、解压完成后,在根目录创建my.ini文件,其中内容如下:[mysql]# 设置mysql客户端默认字符集default-character-setutf8[mysqld]#设置3306端口port 3306# 设置mysql的安装目录basedirD:\Pr…

python用turtle画小人-画一个心送给心爱的小姐姐,Python绘图库Turtle

import turtle turtle.setup(1200, 600) #窗口大小 #画心 turtle.color("black", "red") turtle.pensize(2) turtle.speed(10) turtle.up() #提起画笔 turtle.goto(0, 50) turtle.down() def draw_heart(r, angle45): """ :param r:桃心圆的…

vscode emmet默认模板_从零开始配置 vscode

我们在进行开发工作时,选择一个顺手好用的编辑器是必不可免的, 其中 vscode 就是一个很好的选择。它能让你大部分的工作都在编辑器内完成, 大大的提高开发效率~概述vscode 内置了前端相关的基础环境,如emmet扩展。另外的环境则可以通过它自己的插件商城来…

djano 字段不重复_Java 14 发布了,不使用quot;classquot;也能定义类了?还顺手要干掉Lombok!...

2020年3月17日发布,Java正式发布了JDK 14 ,目前已经可以开放下载。在JDK 14中,共有16个新特性,本文主要来介绍其中的一个特性:JEP 359: Records官方吐槽最为致命早在2019年2月份,Java 语言架构师 Brian Goe…