截至目前,您可能已经了解到Jakarta EE 9项目,该项目旨在为EE创新提供新的基础。
Jakarta EE 9是在EE 8之上的迭代发布,主要目的是将所有javax.
包重命名为jakarta.
包。
在一段时间内,我们将为EE 8和EE 9提供等效的Hibernate Validator版本:Hibernate Validator 6.x将保持javax.
包,而Hibernate Validator 7.x将迁移到jakarta.
包。
考虑到许多库依赖于javax.*
包,Java生态系统的完全过渡可能需要数月甚至数年,因此我们将并行维护这两个版本,这也是为什么我们今天发布两个新版本的原因。
总结如下
-
如果您正在使用
javax.*
包,本公告中的6.2部分适用于您 -
如果您正在迁移到Jakarta EE 9和
jakarta.*
包,则应使用7.0版本。
关于使用javax.*
包或jakarta.*
包的一致性很重要,因此只有当您可以将整个堆栈迁移到Jakarta EE 9时,才升级到Hibernate Validator 7。
如果您不能这样做,您应继续使用Hibernate Validator 6.x。
如果您使用Dependabot并且想保持在6.x版本,请在Hibernate Validator 7升级拉取请求中发表评论,包含 |
7个具体变更
Hibernate Validator 7是Jakarta Bean Validation 3的参考实现,它是Jakarta EE 9的一部分。
这意味着它使用jakarta.validation
包。
此外,XML配置文件的命名空间已更改
-
https://jakarta.ee/xml/ns/validation/configuration
是配置的新命名空间(即validation.xml
)。
再次强调,只有当您想要将整个堆栈迁移到Jakarta EE 9时,才升级到7版本。
7和6.2版本的新功能
表达式语言
在Hibernate Validator中,为了使所有内置约束消息正确插值,您需要在类路径中提供表达式语言实现,因为一些默认消息使用了表达式语言功能。
这些消息是您代码的一部分,因此表达式语言对这些消息进行插值不是问题。
问题是,当通过ConstraintValidatorContext
创建带有消息模板的自定义违规时,这些消息也会由表达式语言引擎进行插值。
在大多数情况下,这是安全的。但如果你在消息模板中包含用户输入,你需要非常小心,因为你需要使用addExpressionVariable()
来转义用户输入。
我们已经在以下地方讨论了与此相关的CVE:https://blog.hibernate.com.cn/2020/05/07/hibernate-validator-615-6020-released/ 。当时,我们决定这是一个正常的行为,与SQL注入非常相似:您需要以与编写SQL时相同的方式转义您的参数。我们还使现有文档更清晰,并将警告更加突出。
我们最近收到了一个新的报告,指出一个常用的库没有注意到这一点。这引发了我们之前遗漏的另一个问题:没有符合规范的安全方式。唯一的安全方式是使用Hibernate Validator特定的API。这意味着它不是实现无关的,如果您计划同时支持Hibernate Validator和Apache BVal,可能会出现问题。
这使得我们重新考虑了这种情况,我们决定深刻改变Hibernate Validator中处理表达式语言的方式,主要变化包括
-
默认情况下,表达式语言对自定义违规是禁用的,即您从
ConstraintValidatorContext
创建的那些。 -
您可以根据每个案例单独启用它,这意味着您可以在保持安全的情况下为特定的自定义违规启用EL。
-
对于约束消息,默认情况下不再允许在您的表达式中调用bean方法。您可以访问bean属性,但不能调用bean方法。
-
您可以分别针对约束和自定义违规对要启用的EL功能进行微调。
我们引入了表达式语言功能级别的概念,它定义了Expression Language引擎启用了哪些功能。
我们目前接受四个特征级别的值
-
NONE
:完全禁用表达式语言插值。 -
VARIABLES
:允许通过addExpressionVariable()
注入的变量、资源包的使用以及formatter
对象的插值。 -
BEAN_PROPERTIES
:允许VARIABLES
允许的一切,以及bean属性的插值。 -
BEAN_METHODS
:还允许执行bean方法。对于硬编码的约束消息可以认为是安全的,但对于需要额外注意的自定义违规则不是。
BEAN_PROPERTIES
是约束的默认值。
NONE
是自定义违规的默认值。如果本地启用但没有指定功能级别,它将使用VARIABLES
功能级别。
以下示例显示了如何为自定义违规启用表达式语言
public class SafeValidator implements ConstraintValidator<ZipCode, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if ( value == null ) {
return true;
}
HibernateConstraintValidatorContext hibernateContext = context.unwrap(
HibernateConstraintValidatorContext.class );
hibernateContext.disableDefaultConstraintViolation();
if ( isInvalid( value ) ) {
hibernateContext
.addExpressionVariable( "validatedValue", value )
.buildConstraintViolationWithTemplate( "${validatedValue} is not a valid ZIP code" )
.enableExpressionLanguage() (1)
.addConstraintViolation();
return false;
}
return true;
}
private boolean isInvalid(String value) {
// ...
return false;
}
}
1 | 为自定义违规启用表达式语言支持,使用默认的功能级别VARIABLES 。 |
请注意,如果需要,您可以定义更宽松的功能级别。但请非常小心,如果将用户输入包含到您的消息模板中,请使用addExpressionVariable()
。
您可以在文档中了解更多关于所有这些信息
虽然绝对不建议,但您可以通过使用本段末尾描述的两个属性,在不更改代码的情况下回到之前的行为。请参阅我们的文档中的这两个属性。
获取 6.2.0.Final 版本
要使用 Maven、Gradle 等获取发布版本,请使用 GAV 坐标 org.hibernate.validator:{hibernate-validator|hibernate-validator-cdi|hibernate-validator-annotation-processor}:6.2.0.Final。请注意,group id 从 org.hibernate
(Hibernate Validator 5 及更早版本)更改为 org.hibernate.validator
(从 Hibernate Validator 6 开始)。
获取 7.0.0.Final 版本
要使用 Maven、Gradle 等获取发布版本,请使用 GAV 坐标 org.hibernate.validator:{hibernate-validator|hibernate-validator-cdi|hibernate-validator-annotation-processor}:7.0.0.Final。请注意,group id 从 org.hibernate
(Hibernate Validator 5 及更早版本)更改为 org.hibernate.validator
(从 Hibernate Validator 6 开始)。
反馈、问题、想法?
要联系,请使用常规渠道
-
用户论坛(使用问题、一般反馈)
-
问题跟踪器(错误报告、功能请求)
-
邮件列表(与开发相关的讨论)
-
Jakarta Bean Validation 开发邮件列表(关于 Jakarta Bean Validation 规范的讨论)