Top 5 Magento Secure
Coding Best Practices
Alex Zarichnyi, Magento ECG
Security in Magento
• Dedicated team
Security in Magento
• Dedicated team
• External audits
Security in Magento
• Dedicated team
• External audits
• Awareness about
OWASP Top 10
Security in Magento
http://magento.com/security
• Bug bounty program
• Dedicated team
• External audits
• Awareness about
OWASP Top 10
up to
$10.000
Security in Magento
• Built-in security
mechanisms
• Bug bounty program
• Dedicated team
• External audits
• Awareness about
OWASP Top 10
Top 5 Secure Coding
Practices
#1. Validate input as strictly as
possible
Input Validation
Do not trust:
• all input parameters
• cookie names and values
• HTTP header content
• Some $_SERVER parameters (e.g.
HTTP_X_FORWARDED, HTTP_X_FORWARD
ED_FOR)
Zend_Validate
• Alpha-numeric values
• Credit Carts
• Host names
• IPs
• Custom validators
(Mage_Core_Model_Url_Validator)
• and many more
$attributeCode = $this->getRequest()->getParam('attribute_code');
$validator = new Zend_Validate_Regex(array(
'pattern' => '/^[a-z][a-z_0-9]{1,254}$/'));
if (!$validator->isValid($attributeCode)) {
//stop execution and add a session error
}
Validate attribute code
1.
2. $attributeCode = $this->getRequest()->getParam('attribute_code');
$validatorChain = new Zend_Validate();
$validatorChain->addValidator(new Zend_Validate_StringLength(
array('min' => 1, 'max' => 254)))
->addValidator(new Zend_Validate_Alnum());
if (!$validatorChain->isValid($attributeCode)) {
//stop execution and add a session error
}
$email = $this->getRequest()->getParam('email');
if (Zend_Validate::is($email, 'EmailAddress')) {
//continue execution
} else {
$this->_getSession()->addError($this->__('Invalid email address.'));
//redirect back
}
Validate email
#2. Use parameterized queries
(?, :param1)
Working with Data in Magento
$id = $this->getRequest()->getParam(‘id’);
$model->load($id);
$q = $this->getRequest()->getParam(‘q’);
$collection->addFieldToFilter(‘name’, ‘%’ . $q . ‘%’));
secure
secure
$select->where("region.code = '{$requestParam}'");
$res = $this->_getReadAdapter()->fetchRow($select);
$select->where('region.code = ?', $requestParam);
$res = $this->_getReadAdapter()->fetchRow($select);
Bad code
Good code
1.
$select->where('region.code= :regionCode');
$bind = array('regionCode' => $requestParam);
$res = $this->getReadAdapter()->fetchRow($select, $bind));
2.
name' ); UPDATE admin_user
SET password =
'34e159c98148ff85036e23986
6a8e053:v6' WHERE
username = 'admin';
$select->joinInner(
array('i' => $this->getTable('enterprise_giftregistry/item')),
'e.entity_id = i.entity_id AND i.item_id = ' . $requestParam,
array()
);
$select->joinInner(
array('i' => $this->getTable('enterprise_giftregistry/item')),
'e.entity_id = i.entity_id AND i.item_id = ' . (int) $requestParam,
array()
);
Bad code
Good code
1; DROP TABLE customer_entity;
$result = "IF (COUNT(*) {$operator} {$requestParam}, 1, 0)";
$select->from(
array('order' => $this->getResource()->getTable('sales/order')),
array(new Zend_Db_Expr($result)
);
$value = $select->getAdapter()->quote($requestParam);
$result = "IF (COUNT(*) {$operator} {$value}, 1, 0)";
$select->from(
array('order' => $this->getResource()->getTable('sales/order')),
array(new Zend_Db_Expr($result))
);
Bad code
Good code
#3. Escape user input
SQL Query Parameters Escaping
$db->quoteInto("WHERE date <
?", "2005-01-02")
WHERE date < '2005-01-02’
Zend_Db_Adapter_Abstract
quote($value, $type = null)
quoteInto($text, $value, $type = null, $count = null)
quoteIdentifier($ident, $auto=false)
quoteColumnAs($ident, $alias, $auto=false)
quoteTableAs($ident, $alias = null, $auto = false)
$db->quote("O'Reilly"); O'Reilly
$db->quote("' or '1'='1' -- “, Zend_Db::FLOAT_TYPE); 0.000000
Mage::helper(‘core’)->escapeHtml($data, $allowedTags = null)
Mage_Core_Block_Abstract::escapeHtml($data, $allowedTags = null)
String Replacement
& &amp;
" &quot;
' &#039;
< &lt;
> &gt;
HTML Special Characters Escaping
https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
Never insert untrusted data except in allowed locations
Use both on frontend & backend
#4. Use CSRF tokens (form
keys)
<form name="myForm" id="myForm" method="post" action="...">
<?php echo $this->getBlockHtml('formkey')?>
<!-- ... -->
</form>
public function saveAction()
{
if (!$this->_validateFormKey()) {
//stop and throw an exception or redirect back
}
}
<input type="hidden"
value="Bcp957eKYP48XL0Y"
name="form_key">
in template
in controller
#5. Use security headers
HTTP security headers
https://www.owasp.org/index.php/List_of_useful_HTTP_headers
Header Description Example
X-XSS-Protection Protects from XSS X-XSS-Protection: 1;
mode=block
X-Frame-Options Protects from Clickjacking X-Frame-Options: deny
X-Content-Type-
Options
Prevents Internet Explorer and
Google Chrome from MIME-
sniffing a response away from the
declared content-type
X-Content-Type-Options:
nosniff
Content-Security-
Policy,
X-WebKit-CSP
Lets you specify a policy for
where content can be loaded
Lets you put restrictions on script
execution
X-WebKit-CSP: default-src
'self'
/**
* Add security headers to the response
*
* @listen controller_action_predispatch
* @param Varien_Event_Observer $observer
*/
public function processPreDispatch(Varien_Event_Observer $observer)
{
$response = $observer->getControllerAction()->getResponse();
$response->setHeader(‘X-XSS-Protection’, ‘1; mode=block’)
->setHeader(‘X-Frame-Options’, ‘DENY’)
->setHeader(‘X-Content-Type-Options’, ‘nosniff’);
}
Additional Resources
• https://www.owasp.org – The Open Web Application Security
Project
• http://websec.io/ – Securing PHP-based applications
• http://cwe.mitre.org/ – Common Weakness Enumeration
• https://www.youtube.com/watch?v=aGnV7P8NXtA –Magento
Security Presentation, Imagine 2012
• http://www.developers-paradise.com/wp-
content/uploads/eltrino-paradise-2013-roman_stepanov.pdf -
Magento Security and Vulnerabilities Presentation, Magento
Developer Paradise 2013
zlik
ozarichnyi@ebay.com
linkedin.com/in/ozarichnyi
Дякую!

Top 5 Magento Secure Coding Best Practices

  • 1.
    Top 5 MagentoSecure Coding Best Practices Alex Zarichnyi, Magento ECG
  • 2.
  • 3.
    Security in Magento •Dedicated team • External audits
  • 4.
    Security in Magento •Dedicated team • External audits • Awareness about OWASP Top 10
  • 5.
    Security in Magento http://magento.com/security •Bug bounty program • Dedicated team • External audits • Awareness about OWASP Top 10 up to $10.000
  • 6.
    Security in Magento •Built-in security mechanisms • Bug bounty program • Dedicated team • External audits • Awareness about OWASP Top 10
  • 7.
    Top 5 SecureCoding Practices
  • 8.
    #1. Validate inputas strictly as possible
  • 9.
    Input Validation Do nottrust: • all input parameters • cookie names and values • HTTP header content • Some $_SERVER parameters (e.g. HTTP_X_FORWARDED, HTTP_X_FORWARD ED_FOR)
  • 10.
    Zend_Validate • Alpha-numeric values •Credit Carts • Host names • IPs • Custom validators (Mage_Core_Model_Url_Validator) • and many more
  • 11.
    $attributeCode = $this->getRequest()->getParam('attribute_code'); $validator= new Zend_Validate_Regex(array( 'pattern' => '/^[a-z][a-z_0-9]{1,254}$/')); if (!$validator->isValid($attributeCode)) { //stop execution and add a session error } Validate attribute code 1. 2. $attributeCode = $this->getRequest()->getParam('attribute_code'); $validatorChain = new Zend_Validate(); $validatorChain->addValidator(new Zend_Validate_StringLength( array('min' => 1, 'max' => 254))) ->addValidator(new Zend_Validate_Alnum()); if (!$validatorChain->isValid($attributeCode)) { //stop execution and add a session error }
  • 12.
    $email = $this->getRequest()->getParam('email'); if(Zend_Validate::is($email, 'EmailAddress')) { //continue execution } else { $this->_getSession()->addError($this->__('Invalid email address.')); //redirect back } Validate email
  • 13.
    #2. Use parameterizedqueries (?, :param1)
  • 14.
    Working with Datain Magento $id = $this->getRequest()->getParam(‘id’); $model->load($id); $q = $this->getRequest()->getParam(‘q’); $collection->addFieldToFilter(‘name’, ‘%’ . $q . ‘%’)); secure secure
  • 15.
    $select->where("region.code = '{$requestParam}'"); $res= $this->_getReadAdapter()->fetchRow($select); $select->where('region.code = ?', $requestParam); $res = $this->_getReadAdapter()->fetchRow($select); Bad code Good code 1. $select->where('region.code= :regionCode'); $bind = array('regionCode' => $requestParam); $res = $this->getReadAdapter()->fetchRow($select, $bind)); 2. name' ); UPDATE admin_user SET password = '34e159c98148ff85036e23986 6a8e053:v6' WHERE username = 'admin';
  • 16.
    $select->joinInner( array('i' => $this->getTable('enterprise_giftregistry/item')), 'e.entity_id= i.entity_id AND i.item_id = ' . $requestParam, array() ); $select->joinInner( array('i' => $this->getTable('enterprise_giftregistry/item')), 'e.entity_id = i.entity_id AND i.item_id = ' . (int) $requestParam, array() ); Bad code Good code 1; DROP TABLE customer_entity;
  • 17.
    $result = "IF(COUNT(*) {$operator} {$requestParam}, 1, 0)"; $select->from( array('order' => $this->getResource()->getTable('sales/order')), array(new Zend_Db_Expr($result) ); $value = $select->getAdapter()->quote($requestParam); $result = "IF (COUNT(*) {$operator} {$value}, 1, 0)"; $select->from( array('order' => $this->getResource()->getTable('sales/order')), array(new Zend_Db_Expr($result)) ); Bad code Good code
  • 18.
  • 19.
    SQL Query ParametersEscaping $db->quoteInto("WHERE date < ?", "2005-01-02") WHERE date < '2005-01-02’ Zend_Db_Adapter_Abstract quote($value, $type = null) quoteInto($text, $value, $type = null, $count = null) quoteIdentifier($ident, $auto=false) quoteColumnAs($ident, $alias, $auto=false) quoteTableAs($ident, $alias = null, $auto = false) $db->quote("O'Reilly"); O'Reilly $db->quote("' or '1'='1' -- “, Zend_Db::FLOAT_TYPE); 0.000000
  • 20.
    Mage::helper(‘core’)->escapeHtml($data, $allowedTags =null) Mage_Core_Block_Abstract::escapeHtml($data, $allowedTags = null) String Replacement & &amp; " &quot; ' &#039; < &lt; > &gt; HTML Special Characters Escaping https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet Never insert untrusted data except in allowed locations Use both on frontend & backend
  • 21.
    #4. Use CSRFtokens (form keys)
  • 22.
    <form name="myForm" id="myForm"method="post" action="..."> <?php echo $this->getBlockHtml('formkey')?> <!-- ... --> </form> public function saveAction() { if (!$this->_validateFormKey()) { //stop and throw an exception or redirect back } } <input type="hidden" value="Bcp957eKYP48XL0Y" name="form_key"> in template in controller
  • 23.
  • 24.
    HTTP security headers https://www.owasp.org/index.php/List_of_useful_HTTP_headers HeaderDescription Example X-XSS-Protection Protects from XSS X-XSS-Protection: 1; mode=block X-Frame-Options Protects from Clickjacking X-Frame-Options: deny X-Content-Type- Options Prevents Internet Explorer and Google Chrome from MIME- sniffing a response away from the declared content-type X-Content-Type-Options: nosniff Content-Security- Policy, X-WebKit-CSP Lets you specify a policy for where content can be loaded Lets you put restrictions on script execution X-WebKit-CSP: default-src 'self'
  • 25.
    /** * Add securityheaders to the response * * @listen controller_action_predispatch * @param Varien_Event_Observer $observer */ public function processPreDispatch(Varien_Event_Observer $observer) { $response = $observer->getControllerAction()->getResponse(); $response->setHeader(‘X-XSS-Protection’, ‘1; mode=block’) ->setHeader(‘X-Frame-Options’, ‘DENY’) ->setHeader(‘X-Content-Type-Options’, ‘nosniff’); }
  • 26.
    Additional Resources • https://www.owasp.org– The Open Web Application Security Project • http://websec.io/ – Securing PHP-based applications • http://cwe.mitre.org/ – Common Weakness Enumeration • https://www.youtube.com/watch?v=aGnV7P8NXtA –Magento Security Presentation, Imagine 2012 • http://www.developers-paradise.com/wp- content/uploads/eltrino-paradise-2013-roman_stepanov.pdf - Magento Security and Vulnerabilities Presentation, Magento Developer Paradise 2013
  • 27.