check for currently unsafe json-ld constructs

This commit is contained in:
Mario
2026-05-05 10:44:17 +00:00
parent 1553bc708f
commit 67d73f74ac
2 changed files with 47 additions and 10 deletions

View File

@@ -8,9 +8,10 @@ class LDSignatures {
static function verify($data,$pubkey) { static function verify($data,$pubkey) {
$expand_and_check_unsafe = true;
$ohash = self::hash(self::signable_options($data['signature'])); $ohash = self::hash(self::signable_options($data['signature']), $expand_and_check_unsafe);
$dhash = self::hash(self::signable_data($data)); $dhash = self::hash(self::signable_data($data), $expand_and_check_unsafe);
$x = Crypto::verify($ohash . $dhash,base64_decode($data['signature']['signatureValue']), $pubkey); $x = Crypto::verify($ohash . $dhash,base64_decode($data['signature']['signatureValue']), $pubkey);
logger('LD-verify: ' . intval($x)); logger('LD-verify: ' . intval($x));
@@ -74,11 +75,11 @@ class LDSignatures {
return json_encode($newopts,JSON_UNESCAPED_SLASHES); return json_encode($newopts,JSON_UNESCAPED_SLASHES);
} }
static function hash($obj) { static function hash($obj, $expand_and_check_unsafe = false) {
return hash('sha256', self::normalise($obj)); return hash('sha256', self::normalise($obj, $expand_and_check_unsafe));
} }
static function normalise($data) { static function normalise($data, $expand_and_check_unsafe) {
$ret = ''; $ret = '';
if(is_string($data)) { if(is_string($data)) {
@@ -90,6 +91,15 @@ class LDSignatures {
jsonld_set_document_loader('jsonld_document_loader'); jsonld_set_document_loader('jsonld_document_loader');
if ($expand_and_check_unsafe) {
$expanded = jsonld_expand($data);
if (self::contains_unsafe_keys($expanded)) {
logger('contains_unsafe_keys: ' . print_r($data,true));
throw new \Exception('json-ld graph modification operation detected');
}
}
try { try {
$ret = jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]); $ret = jsonld_normalize($data,[ 'algorithm' => 'URDNA2015', 'format' => 'application/nquads' ]);
} }
@@ -132,6 +142,33 @@ class LDSignatures {
} }
static function contains_unsafe_keys(array|object $data, int $depth = 0): bool
{
if ($depth > 64) {
return true;
}
$unsafe_keys = ['@graph', '@included', '@reverse'];
if (is_object($data)) {
$data = (array) $data;
}
if (is_array($data)) {
foreach ($data as $key => $value) {
if (in_array($key, $unsafe_keys)) {
return true;
}
if (is_array($value) || is_object($value)) {
if (self::contains_unsafe_keys($value, $depth + 1)) {
return true;
}
}
}
}
return false;
}
} }

View File

@@ -4,7 +4,7 @@
"type": "@type", "type": "@type",
"proof": { "proof": {
"@id": "https://w3id.org/security#proof", "@id": "https://w3id.org/security#proof",
"@type": "@id", "@type": "@id"
}, },
"DataIntegrityProof": { "DataIntegrityProof": {
"@id": "https://w3id.org/security#DataIntegrityProof" "@id": "https://w3id.org/security#DataIntegrityProof"
@@ -35,19 +35,19 @@
}, },
"assertionMethod": { "assertionMethod": {
"@id": "https://w3id.org/security#assertionMethod", "@id": "https://w3id.org/security#assertionMethod",
"@type": "@id", "@type": "@id"
}, },
"authentication": { "authentication": {
"@id": "https://w3id.org/security#authenticationMethod", "@id": "https://w3id.org/security#authenticationMethod",
"@type": "@id", "@type": "@id"
}, },
"capabilityInvocation": { "capabilityInvocation": {
"@id": "https://w3id.org/security#capabilityInvocationMethod", "@id": "https://w3id.org/security#capabilityInvocationMethod",
"@type": "@id", "@type": "@id"
}, },
"capabilityDelegation": { "capabilityDelegation": {
"@id": "https://w3id.org/security#capabilityDelegationMethod", "@id": "https://w3id.org/security#capabilityDelegationMethod",
"@type": "@id", "@type": "@id"
}, },
"keyAgreement": { "keyAgreement": {
"@id": "https://w3id.org/security#keyAgreementMethod", "@id": "https://w3id.org/security#keyAgreementMethod",