如何验证使用 base64UUID 生成的 UUID

Posted

技术标签:

【中文标题】如何验证使用 base64UUID 生成的 UUID【英文标题】:How to validate UUIDs generated using base64UUID 【发布时间】:2021-11-04 09:30:11 【问题描述】:

如何验证使用base64UUID函数生成的UUIDs(即org.elasticsearch.common.UUIDs.base64UUID

我们不希望用户坚持任何不符合上述格式的内容

【问题讨论】:

我相信这里已经回答了:***.com/questions/7905929/how-to-test-valid-uuid-guid 问题不在于 UUID 是否遵循格式,问题在于是否真的是随机生成的 UUID。您应该检查为什么需要这些用户数据。 @josejuan 它是弹性搜索文档的主键 如果您信任客户端,则不应检查代码,如果无效,您的后端必须抛出异常(无论如何,除非代码以某种方式隔离(例如,它是复合键)我永远不会信任客户)。 【参考方案1】:

这个例子可以验证一个基于随机的base64UUID

如果 base64 字符串是有效的 RFC-4122 UUIDv4,Example.valid() 方法将返回 true

package com.example;

import java.math.BigInteger;
import java.util.Arrays;
import java.util.Base64;

public class Example 

    // returns true if a base64 is a valid RFC-4122 UUIDv4
    public static boolean valid(String base64UUID) 

        // decode the string to a numerical value
        byte[] decoded = Base64.getUrlDecoder().decode(base64UUID);
        byte[] bytes16 = Arrays.copyOf(decoded, 16);
        BigInteger number = new BigInteger(/* positive */ 1, bytes16);

        // check the UUID numerical value (0 .. 2^128)
        final BigInteger minimum = BigInteger.ZERO;
        final BigInteger maximum = BigInteger.ONE.shiftLeft(128); // 2^128
        boolean value = number.compareTo(minimum) >= 0 && number.compareTo(maximum) <= 0;

        // check the RFC-4122 version (byte6 = 0011xxxx)
        boolean version = (bytes16[6] & 0xff) >>> 4 == 4;

        // check the RFC-4122 variant (byte8 = 10xxxxxx)
        boolean variant = (bytes16[8] & 0xff) >>> 6 == 2;

        return value && version && variant;
    

    public static void main(String[] args) 

        String[] samples =  //
                // VALID SAMPLES
                "PQQWfFMgSiitBjGVhxrCbQ", // 3d04167c-5320-4a28-ad06-3195871ac26d
                "bJGoRfu1Qy-6uhSNetIQCg", // 6c91a845-fbb5-432f-baba-148d7ad2100a
                "Gj8czi7tQ6i1xpIgjSh06w", // 1a3f1cce-2eed-43a8-b5c6-92208d2874eb
                "JY5omv7ZQgSdsdNBFFv-rw", // 258e689a-fed9-4204-9db1-d341145bfeaf
                "K2EqshyFRs-K_gajQl7z7g", // 2b612ab2-1c85-46cf-8afe-06a3425ef3ee
                "qfXGIFn0T_WDhTD0kMfuzw", // a9f5c620-59f4-4ff5-8385-30f490c7eecf
                "bEviI0JcTjuofyF7Zz9c8A", // 6c4be223-425c-4e3b-a87f-217b673f5cf0
                "CHi4BqAcTpO7n36mXYDpRw", // 0878b806-a01c-4e93-bb9f-7ea65d80e947
                "be32sQWcTFGH4RApDL1w_Q", // 6dedf6b1-059c-4c51-87e1-10290cbd70fd
                "ZP9Zfu6PQ2GfJCw8YnoPJQ", // 90ff597e-ee8f-4361-9f24-2c3c627a0f25
                // NOT VALID SAMPLES
                "D0EFnxTIEoorQYxlYcawm0", // 3d04167c-5320-4a28-ad06-3195871ac26d << 4 // too big
                "GyRqEX7tUMvuroUjXrSEAo", // 6c91a845-fbb5-432f-baba-148d7ad2100a << 4 // too big
                "Bo_HM4u7UOotcaSII0odOs", // 1a3f1cce-2eed-43a8-b5c6-92208d2874eb << 4 // too big
                "CWOaJr-2UIEnbHTQRRb_q8", // 258e689a-fed9-4204-9db1-d341145bfeaf << 4 // too big
                "K2EqshyF1s-K_gajQl7z7g", // 2b612ab2-1c85-d6cf-8afe-06a3425ef3ee // wrong VErsion
                "qfXGIFn07_WDhTD0kMfuzw", // a9f5c620-59f4-eff5-8385-30f490c7eecf // wrong VErsion
                "bEviI0Jc_juofyF7Zz9c8A", // 6c4be223-425c-fe3b-a87f-217b673f5cf0 // wrong VErsion
                "CHi4BqAcTpPbn36mXYDpRw", // 0878b806-a01c-4e93-db9f-7ea65d80e947 // wrong VAriant
                "be32sQWcTFHn4RApDL1w_Q", // 6dedf6b1-059c-4c51-e7e1-10290cbd70fd // wrong VAriant
                "kP9Zfu6PQ2H_JCw8YnoPJQ", // 90ff597e-ee8f-4361-ff24-2c3c627a0f25 // wrong VAriant
        ;

        for (String s : samples) 
            System.out.println(s + ": " + valid(s));
        
    

这是输出:

PQQWfFMgSiitBjGVhxrCbQ: true
bJGoRfu1Qy-6uhSNetIQCg: true
Gj8czi7tQ6i1xpIgjSh06w: true
JY5omv7ZQgSdsdNBFFv-rw: true
K2EqshyFRs-K_gajQl7z7g: true
qfXGIFn0T_WDhTD0kMfuzw: true
bEviI0JcTjuofyF7Zz9c8A: true
CHi4BqAcTpO7n36mXYDpRw: true
be32sQWcTFGH4RApDL1w_Q: true
ZP9Zfu6PQ2GfJCw8YnoPJQ: true
D0EFnxTIEoorQYxlYcawm0: false
GyRqEX7tUMvuroUjXrSEAo: false
Bo_HM4u7UOotcaSII0odOs: false
CWOaJr-2UIEnbHTQRRb_q8: false
K2EqshyF1s-K_gajQl7z7g: false
qfXGIFn07_WDhTD0kMfuzw: false
bEviI0Jc_juofyF7Zz9c8A: false
CHi4BqAcTpPbn36mXYDpRw: false
be32sQWcTFHn4RApDL1w_Q: false
kP9Zfu6PQ2H_JCw8YnoPJQ: false

这个python脚本被用来生成测试样本:

#!/bin/env python3

from uuid import uuid4

alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" # base-64-url

def basen(number, base, alphabet):
    output = ""
    while number:
        output += alphabet[number % base]
        number //= base
    return output[::-1] or "0"
        
def print_uuid(uuid):

    number = uuid.int
    
    base = 64
    length = 22
    padding = length 
    padding_char = alphabet[0]
    
    encoded = ""
    
    padding = 24
    number = number << 16 # padding with 16 bits (2 bytes)
    
    encoded = basen(number, base, alphabet)
    
    print('"' + encoded.rjust(padding, padding_char)[:length] + '", // ' + str(uuid))

def print_list(size):

    for i in range(0, size):
        uuid = uuid4()
        print_uuid(uuid)


print_list(10)

如果您更喜欢使用专门的库,请查看uuid-creator 中的Base64UrlCodecUuidValidator。对于base64UUIDBase64UrlCodecBase64.getUrlDecoder().decode("") 更有效。这是一个使用 uuid-creator 的较短示例:

    public static boolean valid(String base64UUID) 
        UUID uuid = Base64UrlCodec.INSTANCE.decode(base64UUID);
        return UuidUtil.isRandomBased(uuid);
    

【讨论】:

以上是关于如何验证使用 base64UUID 生成的 UUID的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 中加盐和散列密码

Rails + UUID 生成的模式假定 UUID 是整数而不是字符串

Python uuid生成唯一ID

golang包快速生成base64验证码

Python3 - self语法面向对象内置属性魔法方法

Python3 - self语法面向对象内置属性魔法方法