Photo of Torben Hansen

A TechBlog by Torben Hansen


Freelance Full Stack Web Developer located in Germany.
I create web applications mainly using TYPO3, PHP, Python and JavaScript.
Home Archive Tags

Security considerations when working with TYPO3 Formhandler extension

First of all: This article does not show any existing security problems with formhandler. It shows you two real world examples, which I found on a TYPO3 website I did not create, but had to do maintenence for. I will also show what I have done, to (hopefully) resolve the problems.

The TYPO3 extension formhandler is known as the swiss army knife, when it comes to all kind of forms in TYPO3. Formhandler is flexible in many ways and allows a TYPO3 integrator not just to create complex forms with several validation options, but also to prefill fields when a form is loaded or to save/update fields in the TYPO3 database when a form is successfully submitted. I really like this extension and use it in many projects because of it's clean structure, flexibility and because it is actively maintained.

Formhandler is often not just used to create simple contact forms, but also to provide forms which shows, creates or modifies records from/in the TYPO3 database. If the TYPO3 integrator does not think about security at this point, there are several things that can go wrong.

I'm not really a security expert, so if I write totally nonsence in this article, feel free contact me, so the article will contain correct and helpfull information for others.

Example 1 - PreProcessor_LoadDB and GP variable causing leackage of sensitive data

In the first example, a website user does submit data through a form from a third party extension. After the data is submitted, the user receives an e-mail containing a link to a formhandler page, where the user has to fill out some other form fields. The link, which is sent to the user is like shown below:

http://www.domain.tld/myform.html?formname[uid]=123

The parameter "formname[uid]" contains the uid of the newly created record from the third party extension.

When I opened the form the first time, I did not see anything special (expect from the URL parameter). All form fields where empty, so I asked myself, why the URL contained the parameter. After I had a look at the output of the website, I knew, what the URL was used for. The output of the website contained 3 hidden formfields like shown below:

<input type="hidden" name="formname[uid]" value="123">
<input type="hidden" name="formname[recipientname]" value="John Doe">
<input type="hidden" name="formname[email]" value="[email protected]">

Ouch, now I could easily find out, who else did submit data through the form from the third party extension by just increasing/decreasing the uid. The original TYPO3 integrator used a PreProcessor_LoadDB preprocessor to load the additional data in the hidden fields.

Depending on how the database lookup is integrated, it could result in a SQL injection, if you just pass the given UID directly to the select.where of the PreProcessor_LoadDB preprocessor.

Example 2 - Finisher_DB and GP variable causing unwanted data manipulation

The second example uses the same form as shown in example 1. When a website user fills out the form, all fields get submitted to the server and an e-mail ist sent with a Finisher_Mail finisher. As you may guess, the recipient email is taken from the hidden input field, which in case is very bad, since you just can replace the e-mail address in the hidden field with another e-mail address and after form submission, a totally different recipient will receive an e-mail sent from the server.

If you don't think it can get worst, it actually will. The formhandler setup did also contain a Finisher_DB finisher, which updated some fields on a given record in the TYPO3 database. Since the uid to this record is parsed directly through GET/POST variables, it can just be changed and within that, you can just submit the form with different uids and update the fields that the Finisher_DB updates with garbage - of course for all records in the table.

Problem summary and solution approach

All named problems rely on the some cause - user input is just seen as trusted. At no point it is actually checked, if the user has changed the uid or has replaced the values from hidden input fields with own content.

Actually, to take benefit from PreProcessor_LoadDB to prefill fields with Database values or Finisher_DB to update records, you actually need to know the uid from the record where to fetch/update the desired values. So how can you make sure, that the uid is not changed by the user?

Adding a HMAC to the URL

We can add a second parameter to the URL, that contains the HMAC for the uid parameter. This HMAC will later on be used to validate, if the uid has been modified by the user.

TYPO3 has a HashService (TYPO3\CMS\Extbase\Security\Cryptography\HashService), which can be used to generate and validate HMACs. To generate a HMAC for a given string, the TYPO3 HashService uses the TYPO3 encryption key as shared secret. The function generateHmac($string) returns a HMAC for a given string as shown below (short version without type/encryption key check)

hash_hmac('sha1', $string, $encryptionKey);

The TYPO3 HashService also has a function called validateHmac($string, $hmac) to validate, if the given string matches a given HMAC.

Using the generateHmac function, I end up with formhandler URLs like shown below:

http://www.domain.tld/myform.html?formname[uid]=123&formname[uidhmac]=averylonghmac

Adding HMAC check to formhandler

Formhandler has interceptors, which can be used on init and on save of a form. Init-interceptors are called each time a form is displayed and save-interceptors are called before the form-finishers are executed. So the best approach to add the HMAC check is to do this through an own interceptor.

I created a configurable interceptor, which is able to use the validation functions from the TYPO3 HashService.

The source code for the new interceptor is available in this gist. You can just create an own extension with this class and then use it in the formhandler TypoScript settings. Below follows an example TypoScript setup, which uses the new interceptor.

initInterceptors.1 {
class = Tx_MyFormhandlerExtension_Interceptor_HashService
config {
redirectPage = 11
validateHmac {
fields.uid = uidhmac
}
}
}

The configuration above now validates, if the given uidhmac is the correct HMAC for the given uid. If this validation fails, the user is redirected to a configured page.

You can also use the interceptor with appended HMAC string. Those HMACs are created using the appendHmac function in the HashService. Basically it just takes the given string and appends the HMAC for the string to it. An url could look like shown below.

http://www.domain.tld/myform.html?formname[appendedhmac]=123averylonghmac

To validate the given appended HMAC string you can use the interceptor as shown below.

initInterceptors.1 {
class = Tx_MyFormhandlerExtension_Interceptor_HashService
config {
redirectPage = 11
validateAndStripHmac {
fields.1 = appendedhmac
}
}
}

Conclusion

Nearly all described problems from the two examples have been solved with the new interceptor. A user can now not just increase/decrease the GET/POST parameter uid to retreive the personal data of other users and he/she can may also not be able to update other database records, if the interceptor is also configured as a save-interceptor.

The only problem that remains is, that a user can replace the fetched e-mail-address with different one. I simply resolved this issue by removing the e-mail-address from the output and doing a lookup for it in a special save-interceptor I created.

I've created a patch for formhandler and maybe the new interceptor can make it as a core feature of formhandler.

So always remember: Don't trust user input and always think twice when working with user generated data.