日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

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

發布時間:2025/3/12 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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

總結

以上是生活随笔為你收集整理的java编程规范每行代码窄字符,wiki/0xFE_编程规范.md at master · islibra/wiki · GitHub的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。