7

I am using ruby 2.1.0

I have a json file. For example: test.json

    {
      "item":[
        {"apple": 1},
        {"banana": 2}
      ]
   }

Is it safe to load this file with YAML.load?

    YAML.load(File.read('test.json'))

I am trying to load a file which is in either json or yaml format.

Niroj Shrestha
  • 165
  • 1
  • 1
  • 6
  • safe in what way? can it cause arbitrary code to run? – Uri Agassi Jul 07 '14 at 10:37
  • YAML and JSON are not the same thing at all. Are you trying to load JSON? Or YAML? Your sample looks like JSON, so why not just use `JSON.load`? – Pete Jul 07 '14 at 10:41
  • @Pete I am trying to load a file which is either JSON or YAML. That seemed me to be a combined way. Later if yaml comes this code will not break. – Niroj Shrestha Jul 07 '14 at 10:43
  • @UriAgassi Safe meaning the json is loaded the way it should be. – Niroj Shrestha Jul 07 '14 at 10:45
  • 1
    I would expect the YAML parser to throw an exception when encountering invalid YAML (JSON is not valid YAML), so you could catch any parse exception, and fallback to using `JSON.load`. – Pete Jul 07 '14 at 10:49
  • @Pete Yep thanks for the suggestion. I was worried that YAML.load will parse wrong json without throwing any error. – Niroj Shrestha Jul 07 '14 at 10:55
  • I guess I will try with JSON.parse first then will use YAML.load for the fallback. – Niroj Shrestha Jul 07 '14 at 10:56
  • @NirojShrestha Have you tried it? It's not a hard theory to test. – Pete Jul 07 '14 at 10:56
  • 3
    @Pete Are you sure JSON is not a valid YAML? See this. http://stackoverflow.com/questions/1726802/what-is-the-difference-between-yaml-and-json-when-to-prefer-one-over-the-other – Niroj Shrestha Jul 07 '14 at 11:11
  • JSON is supposed to be a subset of YAML. There is theoretically valid JSON that isn't valid YAML, but I haven't encountered any. Loading JSON with a YAML library should work. – Some Guy Jul 07 '14 at 14:12
  • @NirojShrestha YAML version 1.2+, so you need to check the YAML parser. – Elliott Frisch Jul 07 '14 at 19:45

2 Answers2

14

YAML can load JSON

YAML.load('{"something": "test", "other": 4 }')
=> {"something"=>"test", "other"=>4}

JSON will not be able to load YAML.

JSON.load("- something\n")
JSON::ParserError: 795: unexpected token at '- something'

There will be some obscure cases that work and produce different output.

YAML.load("")
=> false
JSON.load("")
=> nil

But generally the YAML construct is not JSON compliant.

So, try the JSON.load first because it's probably better at obscure JSON things.
Catch the JSON::ParserError error and fall back to YAML.load.

Matt
  • 68,711
  • 7
  • 155
  • 158
  • No it isn't, you should use safe_load: https://arp242.net/yaml-config.html – Stefan Steiger Jul 02 '19 at 15:04
  • @StefanSteiger What are you referring to by "No it isn't"? – Matt Jul 03 '19 at 02:24
  • Well, the question was "is it safe" to load json with yaml.load. The answer is no, not with YAML.load, only with YAML.safe_load. - Otherwise, code injection is possible. – Stefan Steiger Jul 03 '19 at 18:56
  • @StefanSteiger OP clarifies in his comments that he's trying to load either json or yaml rather than the security "safe". – Matt Jul 03 '19 at 23:09
  • Yea, that's true, but it's still wrong. You can also just use YAML.safe_load, and then it will work for JSON and YAML (since YAML by definition is a superset of JSON - at least in theory), AND BE SAFE. If the YAML-parser would fail on ANY json, that would be a bug in the yaml-parser. – Stefan Steiger Jul 04 '19 at 12:48
  • Neither is right or wrong, that depends on use case but your comments have highlighted that if you don't need the extended yaml ruby data structures or are loading data from an untrusted source, `safe_load` should be used. – Matt Jul 05 '19 at 00:22
0

In recent work I did I found a corner case of the sort alluded to by Matt. For example

puts JSON.load('{"x": "foo\/bar"}')['x']

succeeds in printing

foo/bar

despite the gratuitous escaping¹ whereas

puts YAML.load('{"x": "foo\/bar"}')['x']

fails:

Psych::SyntaxError ((<unknown>): found unknown escape character while parsing a quoted scalar at line 1 column 7)

¹In this case by Java as per net.sf.json.util.JSONUtils.quote. Note that they forgot to do the same quoting in their own Javadoc, ironically enough, so you have to browse source to understand!

Jesse Glick
  • 24,539
  • 10
  • 90
  • 112
  • nice [bug](https://github.com/ruby/psych/commit/bb7585be12c7865e7eaa60e602c3296621e41e09#diff-e401e3bc7fe7938ad526dd080235d28f7bb0e145f6974c58ae28f5c0d473ef38L3160) in psychs libyaml – Matt Jul 30 '21 at 06:39