I am having trouble implementing CSP with nonce and I'm not understanding what I am doing wrong. I am able to execute local scripts which I'm assuming is allowed the the 'self' parameter. However when I try to submit a contact form which onsubmit execute a return on a js function that sends a post request to a php file to send a email it apparently qualifies as an inline script execution and get blocked by CSP. I have tried to implement nonce in various ways but I'm just not understanding how to enable its execution without using 'unsafe-inline'. Any help would be appreciated. I'm using the following code:
I am specifically getting an error for inline executing from the 'script-src' policy
.htaccess
Header set Content-Security-Policy "default-src 'self'; script-src 'self' 'strict-dynamic' 'nonce-12345678' https://example.com; style-src 'self' 'unsafe-inline'; base-uri 'self'; script-src-elem 'self'; img-src 'self' data:; form-action 'self'; report-to csp-endpoints"
contact.html
<form id="contact_form" onsubmit="return submitForm()" nonce="12345678>
<script src="/js/contact.js" nonce="12345678"></script>
contact.js
function submitForm(e) {
// do stuff
const request = new XMLHttpRequest();
request.open("POST", "php/email.php", true);
request.setRequestHeader("Content-type", "application/json");
request.onload = function () {
if (request.status >= 200 && request.status < 400) {
const resp = request.responseText;
const data = JSON.parse(resp);
alert(`Thank you ${data.name} for your message. We will get back to you at ${data.email} as soon as possible.`);
} else {
alert("Something went wrong. Please try again later.");
console.log(request.responseText);
}
};
request.onerror = function () {
alert("An error occured. Please try again later.");
};
const data = JSON.stringify({
name,
email,
goal,
itsatrap,
requirements,
integrations,
features,
guidelines
});
request.send(data);
return false;
}
}
email.php
<?php
// do stuff
header('Content-Type: application/json');
if (mail($recipient, $subject, $email_content, $email_headers)) {
http_response_code(200);
$json = array("success" => true, "message" => "Thank You! Your message has been sent.", "name" => $name, "email" => $email);
echo json_encode($json, JSON_PRETTY_PRINT);
exit;
} else {
http_response_code(500);
$json = array("success" => false, "message" => "Oops! Something went wrong and we couldn't send your message.", "reason" => error_get_last());
echo json_encode($json, JSON_PRETTY_PRINT);
exit;
}
CodePudding user response:
Thank you @Sebastian Simon. I am now able to use 'strict-dynamic' I realize now why I was getting the errors. I made the following changes to avoid inline execution.
.htaccess
Header set Content-Security-Policy "default-src 'self'; script-src 'self' 'strict-dynamic' https://example.com; style-src 'self' 'unsafe-inline'; base-uri 'self'; script-src-elem 'self'; img-src 'self' data:; form-action 'self'; report-to csp-endpoints"
contact..html
<form id="contact_form" >
<script src="/js/contact.js"></script>
contact.js
async function submitForm() {
// do stuff
const response = await fetch("php/email.php", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
});
if (response.ok) {
const data = await response.json();
alert(`Thank you ${data.name} for your message. We will get back to you at ${data.email} as soon as possible.`);
return true;
} else {
alert("Something went wrong. Please try again later.");
console.log(response);
return false;
}
}
document.getElementById('contact_form').addEventListener('submit', (e) => {
e.preventDefault();
const submitted = submitForm();
if (submitted) {
document.getElementById('contact_form').reset();
}
});