通过Java数字签名提供XML安全
众所周知,XML在产品和项目开发中起着非常重要的作用。 可以从XML文档中获取很多信息。 也可以使用XML文件执行CRUD (添加、查询、更新、删除)操作。 但是,请注意如何确保XML中的数据来自经过身份验证的受信任源。 XML文件数据的可靠性和完整性存在很多问题。 开发人员通常直接处理XML文件,而不考虑数据的可靠性。 一些情况提出了上面的所有问题。 在现实生活中,每当我们收到邮局的来信,我们怎么判断这封信是来自我们的朋友? 根据雪白包的习惯用语、语言、邮件的详细地址等。 可能是雪白包的个性标志。 现在,我们收到的信可能被某人篡改了,增加了其他内容。 出于这些原因,通常我们会验证朋友的手写签名。 当然,这些是关于邮局发来的普通邮件。 电子信息该怎么办? 如何验证电子消息的真实性? 这种情况下采用数字签名。 本文简要介绍了确保数据完整性的XML数字签名技术,并演示了如何将数字签名及其验证过程附加到XML文件。
使用的技术
近几年,XML数字签名发展迅速,特别是在金融领域。 在开始讨论之前,让我们先想想典型的情景。 设想一个组织正在用XML文件将所有员工的工资内容发送到所得税部门。 那么,现在的问题是所得税部门如何验证这个XML文件。 这意味着IT部门必须验证组织的敏感信息。 IT部门必须确保XML文件的来源可靠,并且在IT部门收到之前没有篡改——,即文档内容在分发过程中没有更改。 首先,我们需要理解数字签名的概念。 数字签名是用于验证文档是由受信任的人发送的电子签名。 这可以确保文档的原始内容在传输过程中没有更改。 由于数字签名可以用于加密或未加密的邮件,收件人可以标识发件人,并确保邮件没有被其他用户修改。 根据维基百科的定义,“数字签名是验证数字信息和文档的数学方法”。 有效的数字签名允许收件人验证收到的消息来自已知发件人。 发件人不能否认自己发送了此消息。 “提供认证和不可否认性。 ”而且,此消息在发送过程中不会被修改。 “提供完整性。 ”。 数字签名通常用于软件发布、金融交易和其他需要检测伪造和篡改的重要场合。
现在,让我们看看带有数字签名的完整XML文件。
DDLab Inc
SBC-12345789
约翰亚伯拉罕
SB-001
1234
bipasha基本
SB-002
2334
Vidya Balan
SB-003
3465
Debadatta Mishra
SB-007
5789
Priti Zinta
SB-009
1234
bHS 6uf8KbJV4AGzoHNHLfnXvKM=
auemrct5dzeofsnaznzot0if8wz8kqcmnxdqtoeseonvk 3n qo K9 CTC XRF 3q VX3WP 6810 DDR PDI 6l
E8 ccg 64g E0 hjkoayc5c2l/qkbzwtsbl/oljeufu2dvxbqok 29 ttujfxpvzc 9z F2 PVT1nrj 0f
2/ofHujYZ01D6 YqI8c=
JF ad5 uv 38 l 36 ldzjrqfh9oln 86 vjezxyfaeulrfohlkaxvjlai9hkvbhqrer4TPF dez6isb ksl
6 ihkpnvrakt0x u99 UX i5 qpymswax3qnbqhlw 9z 70 pwyzxysfw4q 2tk2htsguohmuaucif9sbh VF
gbvcRPgxDZZqfIzDmDU=
AQAB
上面是签名的XML文件,可以随时验证。 文件中包含员工姓名、账号和薪资信息。 但是,实际的数字签名是由标签附加的。 标记中的信息提供了文档的完整性。 如您所见,您可以自由修改其中的数据,但该修改将在随后的签名验证中进行检查。
基本上,数字签名有三种。
禁止签名
禁止签名
分离签名
禁止签名
这些签名将签名作为XML对象的子信息,也就是邮件中XML文件的子标记。 封装的数字签名的结构如下
.
路由选择
本文介绍如何在XML封装中创建数字签名。
禁止签名
这样的签名将XML文档包含在Signature对象中。 也就是说,标记是签名XML文件的根元素。 外部签名的结构如下
myxml文档
.
myxml文档
分离签名
在这种情况下,签名是独立生成的,不是XML的一部分。 这意味着您将拥有两个XML文件:要签名的XML文件和XML签名。 分离签名的XML结构如下所示。
.
XML数字签名文件的结构如下:
XML有三个子选项卡,结构如下:
p>这里是XML数字签名的根元素,这一点由W3C建议并且必须遵守。元素是你的签名信息;包含了实际的签名以及使用Base64加密的内容;最后表示公钥。让我们再看一下标签,结构如下:bHS+6uf8KbJV4AGzoHNHLfnXvKM=
当使用Java创建XML数字签名时,SignedInfo对象被用来在数字签名的Signature标签内创建元素。这也是W3C建议的XML签名标准中的一部分。
XML标签的结构如下:
KeyInfo>标记包含了需要数学计算的相关信息,主要有公钥的系数和指数。
要创建XML数字签名可以遵循下列步骤:
生成一组私钥和公钥。
获得原始XML文件。
通过Java API使用私钥和公钥为原始的XML文件签名,生成带有XML签名的文档。
让我们看看使用Java生成XML签名的相关代码:
public void generateXMLDigitalSignature(String originalXmlFilePath,
String destnSignedXmlFilePath, String privateKeyFilePath, String publicKeyFilePath) {
// 获取XML文档对象
Document doc = getXmlDocument(originalXmlFilePath);
// 创建XML签名工厂
XMLSignatureFactory xmlSigFactory = XMLSignatureFactory.getInstance("DOM");
PrivateKey privateKey = new KryptoUtil().getStoredPrivateKey(privateKeyFilePath);
DOMSignContext domSignCtx = new DOMSignContext(privateKey, doc.getDocumentElement());
Reference ref = null;
SignedInfo signedInfo = null;
try {
ref = xmlSigFactory.newReference("", xmlSigFactory.newDigestMethod(DigestMethod.SHA1, null),
Collections.singletonList(xmlSigFactory.newTransform(Transform.ENVELOPED,
(TransformParameterSpec) null)), null, null);
signedInfo = xmlSigFactory.newSignedInfo(
xmlSigFactory.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE,
(C14NMethodParameterSpec) null),
xmlSigFactory.newSignatureMethod(SignatureMethod.RSA_SHA1, null),
Collections.singletonList(ref));
} catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
} catch (InvalidAlgorithmParameterException ex) {
ex.printStackTrace();
}
// 传入公钥路径
KeyInfo keyInfo = getKeyInfo(xmlSigFactory, publicKeyFilePath);
// 创建新的XML签名
XMLSignature xmlSignature = xmlSigFactory.newXMLSignature(signedInfo, keyInfo);
try {
// 对文档签名
xmlSignature.sign(domSignCtx);
} catch (MarshalException ex) {
ex.printStackTrace();
} catch (XMLSignatureException ex) {
ex.printStackTrace();
}
// 存储签名过的文档
storeSignedDoc(doc, destnSignedXmlFilePath);
}
XML签名验证
数字签名的验证包含以下操作:
验证数字签名
计算元素摘要。
使用公钥解密元素。
比较上面两个值。
计算引用摘要
重新计算元素引用摘要。
将它们与中的摘要比较。
为了验证XML签名文档,需要完成下列步骤
得到XML文档和公钥。
验证 元素的数字签名。
计算 元素的摘要并对值进行比较。
让我们看看下面这段XML数字签名示例代码:
public static boolean isXmlDigitalSignatureValid(String signedXmlFilePath, String pubicKeyFilePath) throws Exception {
boolean validFlag = false;
Document doc = getXmlDocument(signedXmlFilePath);
NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
if (nl.getLength() == 0) {
throw new Exception("No XML Digital Signature Found, document is discarded");
}
PublicKey publicKey = new KryptoUtil().getStoredPublicKey(pubicKeyFilePath);
DOMValidateContext valContext = new DOMValidateContext(publicKey, nl.item(0));
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
XMLSignature signature = fac.unmarshalXMLSignature(valContext);
validFlag = signature.validate(valContext);
return validFlag;
}
如上面示例代码所示,XML签名可以通过重新计算的摘要值进行验证,验证算法由 元素指定;使用公钥可以验证摘要中 的值是否正确。 引用摘要会在元素中重新计算,并与 元素中对应的 进行比对。接下来,让我们熟悉一下XML数字签名相关的Java组件。
XMLSignatureFactory
XMLSignatureFactory是生成XML文档数字签名的工厂对象。对象的创建如下列代码所示:
XMLSignatureFactory factory = XMLSignatureFactory.getInstance("DOM");
DOMSignContext
DOMSignContext对象用来生成DOM树。在创建数字签名的过程中,DOM树会被附上XML数字签名。DOMSignContext对象要求输入私钥和XML文档的根元素。
Reference
Reference对象用来在Signature 标记的SignedInfo内部创建XML数字签名。对象创建的遵循“W3C XML签名文法和处理”规则。Reference的基本结构如下:
bHS+6uf8KbJV4AGzoHNHLfnXvKM=
SignedInfo
类似的,SignedInfo对象可以在数字签名的Signature标记内部创建元素。创建的规则同样遵循“W3C XML数字签名协议”。SignedInfo的基本结构如下:
bHS+6uf8KbJV4AGzoHNHLfnXvKM=
XMLSignature
最后,XMLSignature对象用来创建XML文档的封面签名。按照W3C的建议,签名对象应该作为XML数字签名的根元素。
完整的结构如下:
bHS+6uf8KbJV4AGzoHNHLfnXvKM=
aUEMrCT5dzeOfSNaznzoT0If8WZ8KQcMNXDqtoeseonVk3NqOk9ctcxrf3QVX3wP6810DDRPdI6l
e8ccG64Ge0HjkO+aYC5+c2L/qKBzwtSbl/olJEuFU2DVxBQO+K29TTUJfxpVzC9Zf2pvT+1NRj0f
2/ofHujYZ01D6+YqI8c=
jfAd5uV38L36+lDZJrqfH9oLN86VJezXYfAeU+lrFoHlKAXVJLAi9hKvBHQRer4tPfdez6iSBKsl
6IHkPnVRAKt0xU99uxi5QpymsWAX3qnBqHlw9Z70PwyZ+Xysfw4Q2tK2HtSgUOhMuaUcIf9sbHvf
gbvcRPgxDZZqfIzDmDU=
AQAB
为了有一个完成的理解,可以从这里下载完整的Netbeans项目代码。
可以用你最喜欢的Java IDE对项目进行配置;也可以在source文件夹下运行程序。这个项目已经包含了公钥和私钥。如果想要自己生成,可以运行 “TestGenerateKeys”类生成一对公钥和私钥。通过指定自己的XMI文件,还可以查看XML签名的生成过程。
以上就是本次我们给大家整理的内容的全部,感谢大家对脚本之家的支持,如果大家还有不明白的可以在下方留言区讨论。