Upload
magento-dev
View
808
Download
3
Embed Size (px)
DESCRIPTION
Top 5 magento secure coding best practices
Citation preview
Top 5 Magento Secure Coding Best
PracticesAlex 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.00
0
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 (X-Forwarded-
For)
Blacklist vs. Whitelist Validation
‘1=1<script></script> ^\d{5}(-\d{4})?$
^(AA|AE|AP|AL|AK|AS|AZ|AR|CA|CO|CT|DE|DC|FM|FL|GA|GU|HI|ID|IL|IN|IA|KS|KY|LA|ME|MH|MD|MA|MI|MN|MS|MO|MT|NE| NV|NH|NJ|NM|NY|NC|ND|MP|OH|OK|OR|PW|PA|PR|RI|SC|SD|TN|TX|UT|VT|VI|VA|WA|WV|WI|WY)$
Zip Code
U.S. State
O’Brian<sCrIpT></sCrIpT>
Attack patterns
What if?
Zend_Validate
• Alnum values• Credit Carts• Host names• IPs• Custom validators
(Mage_Core_Model_Url_Validator)• and many more
$email = $this->getRequest()->getParam('email'); if (!empty($email) && Zend_Validate::is($email, 'EmailAddress')) { //continue execution} else { $this->_getSession()->addError($this->__('Invalid email address.'));}
Validate email
$attributeCode = $this->getRequest()->getParam('attribute_code');$validator = new Zend_Validate_Regex(array( 'pattern' => '/^[a-z][a-z_0-9]{1,254}$/'));if (!$validato->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}
#2. Use parameterized queries(?, :param1)
$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 = '34e159c98148ff85036e239866a8e053: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 aaa_test;
$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(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
& &
" "
' '
< <
> >
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. 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 loadedLets 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
Q&A