■ はじめに
セキュアなランダム文字列生成を考える => 通常、java.util.Randomを利用すると思うが、偏りや再現性があるそうなので セキュアなランダム文字列生成することを考える
目次
【0】実装案 【1】java.util.UUID.randomUUID()を使用する 【2】java.security.SecureRandomを使用する 【3】Commonsを使用する
【0】実装案
【1】java.util.UUID.randomUUID()を使用する => 一意のランダムを生成する 【2】java.security.SecureRandomを使用する => 安全なトークンを生成する 【3】Commons(org.apache.commons.lang.RandomStringUtils)を使用する => Commonsを利用できるなら、簡単に実装できる
【1】java.util.UUID.randomUUID()を使用する
サンプル
import java.util.UUID; public class SampleUuid { public static void main(String[] args) { System.out.println("Length: 123456789|123456789|123456789|123456789|123456789|123456789|"); String token = UUID.randomUUID().toString(); System.out.println("Token : " + token); token = UUID.randomUUID().toString(); System.out.println("Token : " + token); token = UUID.randomUUID().toString(); System.out.println("Token : " + token); } }
出力結果
Length: 123456789|123456789|123456789|123456789|123456789|123456789| Token : 4fe61f65-9742-4fd3-899a-ba50c6ad0b5b Token : 9012be62-d089-402f-8fd2-6e45d9d2743a Token : 086fbf25-f5b6-423f-bb33-8f7dcf2aed3e
【2】java.security.SecureRandomを使用する
API仕様
https://docs.oracle.com/javase/jp/8/docs/api/java/security/SecureRandom.html
サンプル
import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; public class Main { public static void main(String[] args) throws NoSuchAlgorithmException { System.out.println("Length: 123456789|123456789|123456789|123456789|123456789|123456789|"); String token = createToken(40); System.out.println("Token : " + token); token = createToken(-1); System.out.println("Token : " + token); } private static int DEFAULT_TOKEN_LENGTH = 30; public static String createToken(int tokenLength) throws NoSuchAlgorithmException { int length; if (tokenLength <= 1) { length = DEFAULT_TOKEN_LENGTH / 2; } else { length = tokenLength / 2; } try { SecureRandom random = SecureRandom.getInstance("SHA1PRNG"); byte tokenBytes[] = new byte[length]; random.nextBytes(tokenBytes); return DatatypeConverter.printHexBinary(tokenBytes); } catch (NoSuchAlgorithmException ex) { ex.printStackTrace(); throw ex; } } }
出力結果
Length: 123456789|123456789|123456789|123456789|123456789|123456789| Token : 849aca5e34bbba488675cd16edbe228b599bb227 Token : 5bbffc6e3faf33f228ccd651224ad7
参考文献
https://www.websec-room.com/2013/03/05/438
【3】Commonsを使用する
前提条件
https://commons.apache.org/proper/commons-lang/download_lang.cgi
でダウンロードする必要がある
サンプル
import org.apache.commons.lang.RandomStringUtils; public class SampleCommons { public static void main(String[] args) { System.out.println("Length: 123456789|123456789|123456789|123456789|123456789|123456789|"); String token = RandomStringUtils.randomNumeric(10); System.out.println("Token : " + token); token = RandomStringUtils.randomAlphabetic(20); System.out.println("Token : " + token); token = RandomStringUtils.randomAlphanumeric(30); System.out.println("Token : " + token); token = RandomStringUtils.randomAscii(40); System.out.println("Token : " + token); token = RandomStringUtils.random(50, "abcdABCD123456789@#"); System.out.println("Token : " + token); } }
出力結果
Length: 123456789|123456789|123456789|123456789|123456789|123456789| Token : 0752117248 Token : qNCJPWWKtYTSewbaasOP Token : V2jRM8pCFfGtSXwpBUgNcjfZyuexuL Token : gOz}_]A@qyxpR"=[o2(p9gTjVtE.I#{U OT4TWU Token : 1AD7dd#a52aBcC7C8C6CC2C3c78Dc@d@25117717d19C97412a
使用上の注意
* randomAscii() は、空白(半角スペース)も含まれるので注意 * commons-lang2系「import org.apache.commons.lang.RandomStringUtils」と commons-lang3系「import org.apache.commons.lang3.RandomStringUtils;」があるので注意。 ※ このcommons-lang2系/commons-lang3系でトラブった。内容は以下の関連記事を参照のこと。
参考文献
http://kechanzahorumon.hatenadiary.com/entry/2013/05/30/234000
http://blog.sorausagi.org/2009/03/java.html
関連記事
Pythonで セキュアなランダム文字列生成を考える
https://dk521123.hatenablog.com/entry/2021/11/29/110408