Jump to content

Use cases for sanitizer?


ren
 Share

Recommended Posts

Hi,

This is kind of an open ended question, but I find I'm not using $santizer much because the PW API takes care of most sanitization, and I'm wondering if this is actually ok.

Take for example a contact form which creates a page for each message and emails admin. Something like this...

 

Edit: this is incorrect

                // The page's Inputfields run the same sanitizers as processInput() above
                // Optionally with stripTags enabled

See the reply from @teppo

 

$form = $modules->get('InputfieldForm');
$form->action = $page->url;
$fullNameField = $modules->get('InputfieldText');
$fullNameField->name = 'fullName';
$fullNameField->required = 1;
$emailField = $modules->get('InputfieldEmail');
$emailField->name = 'email';
$emailField->required = 1;
$messageField = $modules->get('InputfieldTextarea');
$messageField->name = 'message';
$messageField->required = 1;
$form->append($nameField);
$form->append($emailField);
$form->append($messageField);
$csrfTokenName = $session->CSRF->getTokenName();
$csrfTokenValue = $session->CSRF->getTokenValue();

$fullNameMarkup = '';
$emailMarkup = '';
$messageMarkup = '';

if ($input->post->submit) {
	// processInput assigns $input values to the form Inputfields by calling each Inputfields' setAttribute() method
	// setAttribute() calls setAttributeValue() which does sanitization, e.g.
	// InputfieldText runs $sanitizer->text with stripTags set to false by default
	// InputfieldTextarea runs $sanitizer->textarea with stripTags set to false by default
	// InputfieldEmail runs $sanitizer->email
	$form->processInput($input->post);
	
	// Output needs to be entity encoded
	$fullNameMarkup = $sanitizer->entities($form->fullName->value);
	$emailMarkup = $sanitizer->entities($form->email->value);
	$messageMarkup = $sanitizer->entities(nl2br($form->message->value));
	
	if (!$form->getErrors()) {
		$adminEmail = sendEmailToAdmin($fullNameMarkup, $emailMarkup, $messageMarkup);
		
		if (!$adminEmail) {
			return wireRenderFile($config->paths->templates . 'includes/contact/failure.inc.php', [ 'type' => 'send email' ]);
		}
		
		try {
			$createPage = $pages->add('contact', '/contacts/', [
				// The page's Inputfields run the same sanitizers as processInput() above
				// Optionally with stripTags enabled
				'contact_full_name' => $form->fullName->value,
				'contact_email' => $form->email->value,
				'contact_message' => $form->message->value,
			]);
		} catch (WireException $e) {
			return wireRenderFile($config->paths->templates . 'includes/contact/failure.inc.php', [ 'type' => 'create page', 'error' => $e ]);
		}

		return wireRenderFile($config->paths->templates . 'includes/contact/success.inc.php'
	}
}

return wireRenderFile($config->paths->templates . 'includes/contact/form.inc.php', [
	'fullNameMarkup' => $fullNameMarkup,
	'emailMarkup' => $emailMarkup,
	'messageMarkup' => $messageMarkup,
	'csrfTokenName' => $csrfTokenName,
	'csrfTokenValue' => $csrfTokenValue,
	'errors' => $form->getErrors(),
]);

 

So processInput() ensures the email address is valid, and all markup is entity encoded.

Even stripping tags seems unnecessary since page fields always give entity encoded output unless output formatting is disabled.

So I only really use $sanitizer->entities(), $sanitizer->selectorValue(), and occasionally $sanitizer->name();

Am I missing something?

How do you use $sanitizer?

Edited by ren
Link to comment
Share on other sites

As a one-off example of putting Sanitizer to work, I'm currently working on a module in which I convert template names to pascal case class names, so recently added $sanitizer->pascalCase() came in handy there.

On the other hand, $sanitizer->pageName(), $sanitizer->selectorField(), and $sanitizer->selectorValue() are probably what I've used the most. Even if I know that ProcessWire has some sort of validation built-in, I much prefer to filter data before passing it to ProcessWire: not only does this provide an extra layer of safety, but it also allows me to display more helpful error messages to the end-user.

$sanitizer->option() and $sanitizer->options() are also useful. They're basically shortcut methods to whitelisting values, and who doesn't need a whitelist every now and then?

Some Sanitizer features are more about formatting, really: $sanitizer->truncate() is a good example of this, as it's basically creates excerpts of longer text. Definitely useful.

All in all, it really depends on what you're doing with ProcessWire, where you're getting your input, and so on. If you're handling raw user input a lot, Sanitizer is particularly useful. Similarly if you tend to enforce more specific rules for your data (say, only allow specific values, or specific characters, etc.) you can get a lot out of Sanitizer.

Personally I'm also a firm believer in the "defence in depth" practice: can't have too many layers of protection 🙂

By the way, in your code you mention that Inputfields run Sanitizer methods. It's probably worth noting that Inputfields won't interfere while you're storing data over the API, and thus they won't prevent anything from being saved to the database either. Fieldtypes handle data storage, and Inputfield settings kick in when you edit that value in the Admin.

  • Like 6
Link to comment
Share on other sites

2 hours ago, teppo said:

As a one-off example of putting Sanitizer to work, I'm currently working on a module in which I convert template names to pascal case class names, so recently added $sanitizer->pascalCase() came in handy there.

Ooh, that sounds cool! 👍

2 hours ago, teppo said:

not only does this provide an extra layer of safety, but it also allows me to display more helpful error messages to the end-user.

Yeah, that makes sense.

2 hours ago, teppo said:

$sanitizer->truncate() is a good example of this

Forgot about that lovely new addition! Looking forward to not writing my own functions 😀

2 hours ago, teppo said:

Personally I'm also a firm believer in the "defence in depth" practice: can't have too many layers of protection

Agreed that there's no harm in guarding against any potential changes.

2 hours ago, teppo said:

By the way, in your code you mention that Inputfields run Sanitizer methods. It's probably worth noting that Inputfields won't interfere while you're storing data over the API, and thus they won't prevent anything from being saved to the database either. Fieldtypes handle data storage, and Inputfield settings kick in when you edit that value in the Admin.

AH! 💡Right, so in the example code, $form->processInput applies the Inputfield sanitizers but $pages->add does not?

Thanks for the wide-ranging examples!

  • Like 2
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...