Sunday, February 25, 2018

Immutable fields (21)

There are a couple of dodgy things in the present form submission that allow things to be modified that shouldn't be.

Firstly, some fields in Registration shouldn't be modifiable via the POST interface: for example, the nonce field to identify a particular registration, or the registration status (which will modified, but only by server side code).

At present, they aren't exposed to the end user in editable HTML fields - so it would be unusual for them to be edited accidentally. They do exist as hidden HTML fields, and even if they didn't, they could be added to a POST HTTP request by someone suitably malicious and skilled at reading the source code.

I'd like to prevent those fields from being modified.

A very simple-to-suggest option is that the form data types shouldn't have these fields at all - they should be nothing to do with the user-side wire protocol at all.

But, that fits in quite awkwardly with the idea that we can use a single Registration type both to represent records in the database and fields on the web form: a row either exists everywhere or not at all.

In each iteration of form processing, we have an initial value that we're using to populate all of the form fields. In the definition of registrationDigestiveForm, "status" .: nonEmptyString attaches the status field in Registration to an over-the-wire key/value pair also labelled "status". Instead we can use pure to place a constant value here, coming from that initial Registration. This removes any connection between this field in Registration and the wire protocol - nothing sent in a POST can change this value.

Here's the updated version of registrationDigestiveForm:

registrationDigestiveForm initial = do
  Registration
    <$> "firstname" .: nonEmptyString (Just $ firstname initial)
    <*> "lastname" .: nonEmptyString (Just $ lastname initial)
    <*> "dob" .: dateLikeString (Just $ dob initial)
    <*> "swim" .: DF.bool (Just $ swim initial)
    <*> (pure . nonce) initial
    <*> "email" .: DF.optionalString (email initial)
    <*> (pure . status) initial

Here's the commit for this post. Next, I want to deal with a different kind of bad change that more plausibly will happen even with innocent users: the case of the registration being modified in two places at the same time.

No comments:

Post a Comment