more flexible ABNF for STS?

In talking with a couple folks in the past few days, it seems that there
already is some thinking about adding some additional directives (aka "header
field value tokens") to the STS header field. One such idea is an "EVonly" flag 
with nominal semantics of "accept only an EV cert".

In general, having a header field (or any protocol element) that is a syntactic
moving target is an issue because of the "what to do about deployed
implementations? will they break?" question.

I noticed a suggestion (included below at end of this msg) from Hixie wrt BNF
techniques to address this sort of situation without employing explicit
versioning information in a header field syntax (or any other BNF based syntax)

This seems interesting to me, so I hacked up the below sample syntax to see
what it looks like. Seems like it might be workable, tho it would add a fair
bit to a spec both in terms of syntax specification but also explaining the
technique. But, adding explicit versioning is also a pain.

Below's a couple of quick examples/experiments with re-coding the STS header 
field ABNF grammar using Hixie's ideas.

thoughts?

=JeffH
------

current STS header field syntax ABNF [RFC2616]:

    Strict-Transport-Security =
          "Strict-Transport-Security" ":" "max-age" "=" delta-seconds [ ";"
"includeSubDomains" ]

--------------------

forwards-compatible CURRENT STS header field syntax ABNF:


Strict-Transport-Security = "Strict-Transport-Security" ":" STSDirectiveList

STSDirectiveList        = "" | STSDirective | STSDirective ";" STSDirectiveList

STSDirective            = valid-STSDirective | invalid-STSDirective


valid-STSDirective      = maxAge | includeSubDomains

maxAge                  = "max-age" "=" delta-seconds invalid-extra

includeSubDomains       = [ "includeSubDomains" ] invalid-extra


invalid-extra           = <value>


invalid-STSDirective    = <name> | <name> ":" | <name> ":" <value>
<name>                  = anything but ":" or ";"
<value>                 = anything but ";"

--------------------

backwards- and forwards-compatible NEW STS header field syntax ABNF:


Strict-Transport-Security = "Strict-Transport-Security" ":" STSDirectiveList

STSDirectiveList        = "" | STSDirective | STSDirective ";" STSDirectiveList

STSDirective            = valid-STSDirective | invalid-STSDirective


valid-STSDirective      = maxAge | includeSubDomains | newDirective

maxAge                  = "max-age" "=" delta-seconds invalid-extra

includeSubDomains       = [ "includeSubDomains" ] invalid-extra

newDirective            = "foobar" invalid-extra


invalid-extra           = <value>


invalid-STSDirective    = <name> | <name> ":" | <name> ":" <value>
<name>                  = anything but ":" or ";"
<value>                 = anything but ";"


===============================================================


the below is excerpted from this msg from Hixie..

    Re: Comments on the Content Security Policy specification
    http://www.mail-archive.com/dev-security@lists.mozilla.org/msg01566.html

..on dev-security@lists.mozilla.org.



-------- >8 ---------
Subject: Re: Comments on the Content Security Policy specification
From: Ian Hickson <ian@hixie.ch>
Date: Wed, 29 Jul 2009 22:23:46 +0000 (UTC)
Cc: dev-security@lists.mozilla.org, www-archive@w3.org

<snip/>

  > >>> I don't think UAs should advertise support for this feature in their
  > >>> HTTP requests. Doing this for each feature doesn't scale.
  > >>
  > >> I personally agree for all the reasons you mention, but we still have
  > >> a potential versioning problem to resolve. Or not -- if we do nothing
  > >> we could always add a CSP-2 header in the future if necessary. I'm
  > >> just worried that it's unlikely that we thought of everything the
  > >> first time through.
  > >
  > > Just make sure it's forwards-compatible, so you can add new features,
  > > then you don't need to version it. (The same way HTML and CSS and the
  > > DOM have been designed, for instance.)
  >
  > I think Dan summarized the trade-off nicely here:
  > http://groups.google.com/group/mozilla.dev.security/msg/787c87362d08bf5e
  >
  > I can see why folks want to avoid a version string but several of us
  > have limited confidence in our ability to design with
  > forward-compatibility.  Perhaps you could provide some guidance in this
  > particular area since you have a lot of experience doing so.

Make the BNF that defines the syntax be something that matches all
possible strings.

For example, here is a trivial syntax like that:

     <list>              ::= "" | <directive> | <directive> ";" <list>
     <directive>         ::= <name> | <name> ":" | <name> ":" <value>
     <name>              ::= anything but ":" or ";"
     <value>             ::= anything but ";"

Then, extend this so that it covers the syntax you want to support, and
leaves the invalid stuff in productions with "invalid" in the name, e.g.:

     <list>              ::= "" | <directive> | <directive> ";" <list>
     <directive>         ::= <valid-directive> | <invalid-directive>

     <valid-directive>   ::= <color> | <smell>
     <color>             ::= "color" ":" <color-values> <invalid-extra>
     <color-values>      ::= "red" | "green"
     <smell>             ::= "smell" ":" <smell-values> <invalid-extra>
     <smell-values>      ::= "flower" | "honey"

     <invalid-extra>     ::= <value>

     <invalid-directive> ::= <name> | <name> ":" | <name> ":" <value>
     <name>              ::= anything but ":" or ";"
     <value>             ::= anything but ";"

Then, define that the UA has to parse all input strings into the tree of
directives that it maps to.

So for example, with the above syntax, "foo:bar" would parse to:

     list
      +- directive
          +- invalid-directive
              +- name
              |   +- "foo"
              +- ":"
              +- value
                  +- "bar"

...and "color:red blue" would parse to:

     list
      +- directive
          +- valid-directive
              +- color
                  +- "color:"
                  +- color-values
                  |   +- "red"
                  +- invalid-extra
                      +- value
                          +- " blue"

...then, define how you walk this tree. Typically, you would say that you
ignore any directives that have "invalid" in their name, so the examples
above would be treated as "" and "color:red" respectively.

This then allows you to extend the syntax in both directions -- ignoring
new bits, and ignoring entire directives. For example, "color:red except
orange" would be treated as "color:red" in v1 UAs, whereas
"color:excluding orange from red" would be treated as "".

So, let's look at the example Dan gave. Today, to allow scripts in the
head, you need:

     script-src: inline;

If we ever add a keyword to make only scripts in the head work:

     script-src: head;

...legacy UAs will end up stripping the scripts you wanted kept, thus
causing a backwards-compatibility problem. If you design it with the model
above, you could introduce the feature as the following instead:

     script-src: inline only head;

Legacy UAs would see just "inline", new UAs would see both.

-------- 8< ---------


---
end

Received on Monday, 21 September 2009 23:28:35 UTC