--- CBOR-XS/XS.pm 2016/11/25 23:37:27 1.64 +++ CBOR-XS/XS.pm 2016/11/26 00:47:02 1.65 @@ -66,7 +66,7 @@ use common::sense; -our $VERSION = 1.51; +our $VERSION = 1.6; our @ISA = qw(Exporter); our @EXPORT = qw(encode_cbor decode_cbor); @@ -115,6 +115,31 @@ my $cbor = CBOR::XS->new->encode ({a => [1,2]}); +=item $cbor = new_safe CBOR::XS + +Create a new, safe/secure CBOR::XS object. This is similar to C, +but configures the coder object to be safe to use with untrusted +data. Currently, this is equivalent to: + + my $cbor = CBOR::XS + ->new + ->forbid_objects + ->filter (\&CBOR::XS::safe_filter) + ->max_size (1e8); + +But is more future proof (it is better to crash because of a change than +to be exploited in other ways). + +=cut + +sub new_safe { + CBOR::XS + ->new + ->forbid_objects + ->filter (\&CBOR::XS::safe_filter) + ->max_size (1e8) +} + =item $cbor = $cbor->max_depth ([$maximum_nesting_depth]) =item $max_depth = $cbor->get_max_depth @@ -139,7 +164,7 @@ been chosen to be as large as typical operating systems allow without crashing. -See SECURITY CONSIDERATIONS, below, for more info on why this is useful. +See L, below, for more info on why this is useful. =item $cbor = $cbor->max_size ([$maximum_string_size]) @@ -154,7 +179,7 @@ If no argument is given, the limit check will be deactivated (same as when C<0> is specified). -See SECURITY CONSIDERATIONS, below, for more info on why this is useful. +See L, below, for more info on why this is useful. =item $cbor = $cbor->allow_unknown ([$enable]) @@ -228,6 +253,25 @@ This option does not affect C in any way - shared values and references will always be encoded properly if present. +=item $cbor = $cbor->forbid_objects ([$enable]) + +=item $enabled = $cbor->get_forbid_objects + +Disables the use of the object serialiser protocol. + +If C<$enable> is true (or missing), then C will will throw an +exception when it encounters perl objects that would be encoded using the +perl-object tag (26). When C encounters such tags, it will fall +back to the general filter/tagged logic as if this were an unknown tag (by +default resulting in a C object). + +If C<$enable> is false (the default), then C will use the +L object serialisation protocol to serialise objects +into perl-object tags, and C will do the same to decode such tags. + +See L, below, for more info on why forbidding this +protocol can be useful. + =item $cbor = $cbor->pack_strings ([$enable]) =item $enabled = $cbor->get_pack_strings @@ -339,10 +383,23 @@ creates a C object to hold the tag and the value. When the filter is cleared (the default state), the default filter -function, C, is used. This function simply looks -up the tag in the C<%CBOR::XS::FILTER> hash. If an entry exists it must be -a code reference that is called with tag and value, and is responsible for -decoding the value. If no entry exists, it returns no values. +function, C, is used. This function simply +looks up the tag in the C<%CBOR::XS::FILTER> hash. If an entry exists +it must be a code reference that is called with tag and value, and is +responsible for decoding the value. If no entry exists, it returns no +values. C provides a number of default filter functions already, +the the C<%CBOR::XS::FILTER> hash can be freely extended with more. + +C additionally provides an alternative filter function that is +supposed to be safe to use with untrusted data (which the default filter +might not), called C, which works the same as +the C but uses the C<%CBOR::XS::SAFE_FILTER> variable +instead. It is prepopulated with the tag decoding functions that are +deemed safe (basically the same as C<%CBOR::XS::FILTER> without all +the bignum tags), and can be extended by user code as wlel, although, +obviously, one should be very careful about adding decoding functions +here, since the expectation is that they are safe to use on untrusted +data, after all. Example: decode all tags not handled internally into C objects, with no other special handling (useful when working with @@ -359,6 +416,27 @@ "tag 1347375694 value $value" }; +Example: provide your own filter function that looks up tags in your own +hash: + + my %my_filter = ( + 998347484 => sub { + my ($tag, $value); + + "tag 998347484 value $value" + }; + ); + + my $coder = CBOR::XS->new->filter (sub { + &{ $my_filter{$_[0]} or return } + }); + + +Example: use the safe filter function (see L for +more considerations on security). + + CBOR::XS->new->filter (\&CBOR::XS::safe_filter)->decode ($cbor_data); + =item $cbor_data = $cbor->encode ($perl_scalar) Converts the given Perl data structure (a scalar value) to its CBOR @@ -980,43 +1058,117 @@ =head1 SECURITY CONSIDERATIONS -When you are using CBOR in a protocol, talking to untrusted potentially -hostile creatures requires relatively few measures. +Tl;dr... if you want to decode or encode CBOR from untrusted sources, you +should start with a coder object created via C: + + my $coder = CBOR::XS->new_safe; -First of all, your CBOR decoder should be secure, that is, should not have -any buffer overflows. Obviously, this module should ensure that and I am -trying hard on making that true, but you never know. - -Second, CBOR::XS supports object serialisation - decoding CBOR can cause -calls to I C method in I package that exists in your -process (that is, CBOR::XS will not try to load modules, but any existing -C method or function can be called, so they all have to be secure). - -Third, you need to avoid resource-starving attacks. That means you should -limit the size of CBOR data you accept, or make sure then when your -resources run out, that's just fine (e.g. by using a separate process that -can crash safely). The size of a CBOR string in octets is usually a good + my $data = $coder->decode ($cbor_text); + my $cbor = $coder->encode ($data); + +Longer version: When you are using CBOR in a protocol, talking to +untrusted potentially hostile creatures requires some thought: + +=over 4 + +=item Security of the CBOR decoder itself + +First and foremost, your CBOR decoder should be secure, that is, should +not have any buffer overflows or similar bugs that could potentially be +exploited. Obviously, this module should ensure that and I am trying hard +on making that true, but you never know. + +=item CBOR::XS can invoke almost arbitrary callbacks during decoding + +CBOR::XS supports object serialisation - decoding CBOR can cause calls +to I C method in I package that exists in your process +(that is, CBOR::XS will not try to load modules, but any existing C +method or function can be called, so they all have to be secure). + +Less obviously, it will also invoke C and C methods - +even if all your C methods are secure, encoding data structures from +untrusted sources can invoke those and trigger bugs in those. + +So, if you are not sure about the security of all the modules you +have loaded (you shouldn't), you should disable this part using +C. + +=item CBOR can be extended with tags that call library code + +CBOR can be extended with tags, and C has a registry of +conversion functions for many existing tags that can be extended via +third-party modules (see the C method). + +If you don't trust these, you should configure the "safe" filter function, +C, which by default only includes conversion +functions that are considered "safe" by the author (but again, they can be +extended by third party modules). + +Depending on your level of paranoia, you can use the "safe" filter: + + $cbor->filter (\&CBOR::XS::safe_filter); + +... your own filter... + + $cbor->filter (sub { ... do your stuffs here ... }); + +... or even no filter at all, disabling all tag decoding: + + $cbor->filter (sub { }); + +This is never a problem for encoding, as the tag mechanism only exists in +CBOR texts. + +=item Resource-starving attacks: object memory usage + +You need to avoid resource-starving attacks. That means you should limit +the size of CBOR data you accept, or make sure then when your resources +run out, that's just fine (e.g. by using a separate process that can +crash safely). The size of a CBOR string in octets is usually a good indication of the size of the resources required to decode it into a Perl -structure. While CBOR::XS can check the size of the CBOR text, it might be -too late when you already have it in memory, so you might want to check -the size before you accept the string. - -Fourth, CBOR::XS recurses using the C stack when decoding objects and -arrays. The C stack is a limited resource: for instance, on my amd64 -machine with 8MB of stack size I can decode around 180k nested arrays but -only 14k nested CBOR objects (due to perl itself recursing deeply on croak -to free the temporary). If that is exceeded, the program crashes. To be -conservative, the default nesting limit is set to 512. If your process -has a smaller stack, you should adjust this setting accordingly with the -C method. +structure. While CBOR::XS can check the size of the CBOR text (using +C), it might be too late when you already have it in memory, so +you might want to check the size before you accept the string. + +As for encoding, it is possible to construct data structures that are +relatively small but result in large CBOR texts (for example by having an +array full of references to the same big data structure, which will all be +deep-cloned during encoding by default). This is rarely an actual issue +(and the worst case is still just running out of memory), but you can +reduce this risk by using C. + +=item Resource-starving attacks: stack overflows + +CBOR::XS recurses using the C stack when decoding objects and arrays. The +C stack is a limited resource: for instance, on my amd64 machine with 8MB +of stack size I can decode around 180k nested arrays but only 14k nested +CBOR objects (due to perl itself recursing deeply on croak to free the +temporary). If that is exceeded, the program crashes. To be conservative, +the default nesting limit is set to 512. If your process has a smaller +stack, you should adjust this setting accordingly with the C +method. + +=item Resource-starving attacks: CPU en-/decoding complexity + +CBOR::XS will use the L, L and +L libraries to represent encode/decode bignums. These can +be very slow (as in, centuries of CPU time) and can even crash your +program (and are generally not very trustworthy). See the next section for +details. + +=item Data breaches: leaking information in error messages + +CBOR::XS might leak contents of your Perl data structures in its error +messages, so when you serialise sensitive information you might want to +make sure that exceptions thrown by CBOR::XS will not end up in front of +untrusted eyes. + +=item Something else... Something else could bomb you, too, that I forgot to think of. In that case, you get to keep the pieces. I am always open for hints, though... -Also keep in mind that CBOR::XS might leak contents of your Perl data -structures in its error messages, so when you serialise sensitive -information you might want to make sure that exceptions thrown by CBOR::XS -will not end up in front of untrusted eyes. +=back =head1 BIGNUM SECURITY CONSIDERATIONS @@ -1101,7 +1253,7 @@ =cut -# clumsy hv_store-in-perl +# clumsy and slow hv_store-in-hash helper function sub _hv_store { $_[0]{$_[1]} = $_[2]; } @@ -1187,10 +1339,16 @@ # 36 # mime message rfc2045, utf-8 ); -sub CBOR::XS::default_filter { +sub default_filter { &{ $FILTER{$_[0]} or return } } +our %SAFE_FILTER = map { $_ => $FILTER{$_} } 0, 1, 21, 22, 23, 32; + +sub safe_filter { + &{ $SAFE_FILTER{$_[0]} or return } +} + sub URI::TO_CBOR { my $uri = $_[0]->as_string; utf8::upgrade $uri;