Kein eval
ist nötig. Ihr Problem ist, dass Sie den Wert nicht als JSON-Objekt decodieren.
CREATE OR REPLACE FUNCTION json_update(data json, key text, value json)
RETURNS json AS
$BODY$
from json import loads, dumps
if key is None: return data
js = loads(data)
# you must decode 'value' with loads too:
js[key] = loads(value)
return dumps(js)
$BODY$
LANGUAGE plpythonu VOLATILE;
postgres=# SELECT json_update('{"a":1}', 'a', '{"innerkey":"innervalue"}');
json_update
-----------------------------------
{"a": {"innerkey": "innervalue"}}
(1 row)
Nicht nur das, sondern auch die Verwendung von eval
um json
zu decodieren ist gefährlich und unzuverlässig. Es ist unzuverlässig, weil json
ist nicht Python, es wird einfach die meiste Zeit ein bisschen so ausgewertet. Es ist unsicher, weil man nie weiß, was man auswertet. In diesem Fall sind Sie weitgehend durch den json-Parser von PostgreSQL geschützt:
postgres=# SELECT json_update(
postgres(# '{"a":1}',
postgres(# 'a',
postgres(# '__import__(''shutil'').rmtree(''/glad_this_is_not_just_root'')'
postgres(# );
ERROR: invalid input syntax for type json
LINE 4: '__import__(''shutil'').rmtree(''/glad_this_is_not_...
^
DETAIL: Token "__import__" is invalid.
CONTEXT: JSON data, line 1: __import__...
... aber es würde mich nicht wundern, wenn jemand einen eval
unterschieben kann darüber hinaus ausnutzen. Die Lektion hier also:Verwenden Sie nicht eval
.