Magento


Example of a security attack on your magento store

One of my clients’ sites has a 404 not found logger installed so we can easily add needed redirects. While reviewing the log today it became apparent somebody had run a script against the site to check for a couple hundred combinations of common directories and files that could be downloaded. Many of them were looking for database backup files. The scary thing is, as I’ve worked on dozens of Magento sites, I’ve seen files and directories with these names available publically when I start working on their project. All someone has to do is guess the filename and proper path and they’ll download an older copy of your database – whenever your developer created that file. It’s difficult for a store owner to identify this security risk because most of them aren’t accessing the code files and looking. Be sure to have a development team working on your site that is focused on security and doesn’t leave these files laying around! The good news is, we don’t have any vulnerable data accessible like this on our customers’ project, and we blocked this IP address.


Magento Error Warning: mcrypt_generic_deinit(): Could not terminate encryption specifier

I ran into the below error today while working with Magento 1 and registering a customer during checkout.

[10-Apr-2018 13:49:47] WARNING: [pool www] child 1731 said into stderr: "NOTICE: PHP message: PHP Fatal error:  Uncaught exception 'Exception' with message 'Warning: mcrypt_generic_deinit(): Could not terminate encryption specifier  in /var/www/myproject/htdocs/lib/Varien/Crypt/Mcrypt.php on line 135' in /var/www/myproject/htdocs/app/code/core/Mage/Core/functions.php:245"
[10-Apr-2018 13:49:47] WARNING: [pool www] child 1731 said into stderr: "Stack trace:"
[10-Apr-2018 13:49:47] WARNING: [pool www] child 1731 said into stderr: "#0 [internal function]: mageCoreErrorHandler(2, 'mcrypt_generic_...', '/var/www/myproject...', 135, Array)"
[10-Apr-2018 13:49:47] WARNING: [pool www] child 1731 said into stderr: "#1 /var/www/myproject/htdocs/lib/Varien/Crypt/Mcrypt.php(135): mcrypt_generic_deinit(Resource id #180)"
[10-Apr-2018 13:49:47] WARNING: [pool www] child 1731 said into stderr: "#2 /var/www/myproject/htdocs/lib/Varien/Crypt/Mcrypt.php(54): Varien_Crypt_Mcrypt->_reset()"
[10-Apr-2018 13:49:47] WARNING: [pool www] child 1731 said into stderr: "#3 [internal function]: Varien_Crypt_Mcrypt->destruct()"
[10-Apr-2018 13:49:47] WARNING: [pool www] child 1731 said into stderr: "#4 {main}"
[10-Apr-2018 13:49:47] WARNING: [pool www] child 1731 said into stderr: "  thrown in /var/www/myproject/htdocs/app/code/core/Mage/Core/functions.php on line 245"

The problem is the encryption key in app/etc/local.xml was empty. Add one to solve the problem.


A faceted navigation that’s optimal for both site visitors and SEO

A project of mine suffers from over categorization as described here https://baymard.com/blog/ecommerce-over-categorization . There are too many sub categories, many of which contain just a product or two, that silo the visitor into a cumbersome experience. Imagine you visited a site and viewed their TV’s and you looked at their category for 40″ TVs. But then, you decided to view other TV’s, so you viewed the 42″ category, and then the 46″ category. The same would happen if you wanted to shop TV’s by brand, type, or another feature. It would take a long time to browse all available TV’s with the features that are valuable to you! This is an example of over categorization. Instead the categories should be turned into a TV’s category with a variety of available facets (filters) that can be applied together.

Aside from a good information architecture, site speed is important. An ajax based navigation, such as this one https://www.lacrossetechnology.com/products/weather/weather-stations provides a great user experience because only the products will reload when a filter is applied. An entire page reload when a filter changes is not necessary, which improves performance.

While an ajax based navigation is great for visitors, it’s terrible for search engine optimization because:

  1. The filters (facets) and combinations of filters won’t have unique meta content or in page descriptions like the previous sub categories did. With the previous over categorization there was a separate category for “Sony TV’s” that had a unique URL, page title and meta data, and a unique in page description. This is extremely important for SEO and is lost when switching to a general TV’s category with a brand filter (Sony).

    Solution –
    I was happy to find this Amasty extension https://amasty.com/improved-navigation-ajax-layered-navigation.html solves the problem. Try out the filtering on this demo http://improved-navigation-1910.demo.amasty.com/improved-navigation-1910/women/dresses-skirts/dresses-long.html . Notice I’ve linked you directly to the category page with a few filters applied; the combination of filters produces a unique URL without a query string (dresses-long.html) that is built in the same order every time for consistency. Additionally, this unique set of filters will dynamically change the page’s meta description, heading, and show/hide cms blocks of your choosing. You get the best of both worlds here – ajax driven navigation for the user and unique page content for the search engine. The downside it is takes a fair amount of configuration, but it’s worth it. This is especially important if we’re rearranging site categories and changing unnecessary sub categories, which have link juice, info filters.

  2. The filters (facets) and combinations of filters won’t get indexed by search engines like the previous sub categories did. Take the TV’s category for example – there will be one URL for TV’s that your ecommerce solution, such as Magento, will include in the Google sitemap. If you want to link the visitor directly to Sony TV’s it’s possible but with an ugly URL that won’t be included in the google sitemap by default. This URL will be in the form of a query string like tvs.html?brand=sony&size=46, which are not preferred by search engines.

    Solution –
    Build or buy functionality that will add URL’s of your choosing to the google sitemap. Again Amasty to the rescue with this module that allows you to add URL’s of your choosing https://amasty.com/magento-xml-google-sitemap.html .

I found these related articles helpful
https://moz.com/ugc/guide-to-ecommerce-facets-filters-and-categories
https://moz.com/blog/building-faceted-navigation-that-doesnt-suck
https://www.practicalecommerce.com/SEO-When-Product-Facets-and-Filters-Fail


Clean out Magento test data before launch

Before launching a site to production, or if it’s creating a copy of the website and database for development and testing purposes, you may need to clear out all customer and order information. Kudos to Geoff Jackson for this solution https://www.designhaven.co.uk/2014/08/cleanly-delete-orders-sales-customer-data-magento/ . I’ve used this a few times now and want to include it here for easy reference.

SET FOREIGN_KEY_CHECKS=0;
 
#This may NOT be necessary FOR you, but it was FOR me
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ALLOW_INVALID_DATES';
 
##############################
# SALES RELATED TABLES
##############################
TRUNCATE `sales_flat_creditmemo`;
TRUNCATE `sales_flat_creditmemo_comment`;
TRUNCATE `sales_flat_creditmemo_grid`;
TRUNCATE `sales_flat_creditmemo_item`;
TRUNCATE `sales_flat_invoice`;
TRUNCATE `sales_flat_invoice_comment`;
TRUNCATE `sales_flat_invoice_grid`;
TRUNCATE `sales_flat_invoice_item`;
TRUNCATE `sales_flat_order`;
TRUNCATE `sales_flat_order_address`;
TRUNCATE `sales_flat_order_grid`;
TRUNCATE `sales_flat_order_item`;
TRUNCATE `sales_flat_order_payment`;
TRUNCATE `sales_flat_order_status_history`;
TRUNCATE `sales_flat_quote`;
TRUNCATE `sales_flat_quote_address`;
TRUNCATE `sales_flat_quote_address_item`;
TRUNCATE `sales_flat_quote_item`;
TRUNCATE `sales_flat_quote_item_option`;
TRUNCATE `sales_flat_quote_payment`;
TRUNCATE `sales_flat_quote_shipping_rate`;
TRUNCATE `sales_flat_shipment`;
TRUNCATE `sales_flat_shipment_comment`;
TRUNCATE `sales_flat_shipment_grid`;
TRUNCATE `sales_flat_shipment_item`;
TRUNCATE `sales_flat_shipment_track`;
TRUNCATE `sales_invoiced_aggregated`;
TRUNCATE `sales_invoiced_aggregated_order`;
TRUNCATE `log_quote`;
 
ALTER TABLE `sales_flat_creditmemo_comment` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_creditmemo_grid` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_creditmemo_item` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_invoice` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_invoice_comment` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_invoice_grid` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_invoice_item` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_order` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_order_address` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_order_grid` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_order_item` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_order_payment` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_order_status_history` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_quote` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_quote_address` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_quote_address_item` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_quote_item` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_quote_item_option` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_quote_payment` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_quote_shipping_rate` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_shipment` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_shipment_comment` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_shipment_grid` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_shipment_item` AUTO_INCREMENT=1;
ALTER TABLE `sales_flat_shipment_track` AUTO_INCREMENT=1;
ALTER TABLE `sales_invoiced_aggregated` AUTO_INCREMENT=1;
ALTER TABLE `sales_invoiced_aggregated_order` AUTO_INCREMENT=1;
ALTER TABLE `log_quote` AUTO_INCREMENT=1;
 
#########################################
# DOWNLOADABLE PURCHASED
#########################################
TRUNCATE `downloadable_link_purchased`;
TRUNCATE `downloadable_link_purchased_item`;
 
ALTER TABLE `downloadable_link_purchased` AUTO_INCREMENT=1;
ALTER TABLE `downloadable_link_purchased_item` AUTO_INCREMENT=1;
 
#########################################
# RESET ID COUNTERS
#########################################
TRUNCATE `eav_entity_store`;
ALTER TABLE  `eav_entity_store` AUTO_INCREMENT=1;
 
 
##############################
# CUSTOMER RELATED TABLES
##############################
TRUNCATE `customer_address_entity`;
TRUNCATE `customer_address_entity_datetime`;
TRUNCATE `customer_address_entity_decimal`;
TRUNCATE `customer_address_entity_int`;
TRUNCATE `customer_address_entity_text`;
TRUNCATE `customer_address_entity_varchar`;
TRUNCATE `customer_entity`;
TRUNCATE `customer_entity_datetime`;
TRUNCATE `customer_entity_decimal`;
TRUNCATE `customer_entity_int`;
TRUNCATE `customer_entity_text`;
TRUNCATE `customer_entity_varchar`;
TRUNCATE `tag`;
TRUNCATE `tag_relation`;
TRUNCATE `tag_summary`;
TRUNCATE `tag_properties`;
TRUNCATE `wishlist`;
TRUNCATE `log_customer`;
 
ALTER TABLE `customer_address_entity` AUTO_INCREMENT=1;
ALTER TABLE `customer_address_entity_datetime` AUTO_INCREMENT=1;
ALTER TABLE `customer_address_entity_decimal` AUTO_INCREMENT=1;
ALTER TABLE `customer_address_entity_int` AUTO_INCREMENT=1;
ALTER TABLE `customer_address_entity_text` AUTO_INCREMENT=1;
ALTER TABLE `customer_address_entity_varchar` AUTO_INCREMENT=1;
ALTER TABLE `customer_entity` AUTO_INCREMENT=1;
ALTER TABLE `customer_entity_datetime` AUTO_INCREMENT=1;
ALTER TABLE `customer_entity_decimal` AUTO_INCREMENT=1;
ALTER TABLE `customer_entity_int` AUTO_INCREMENT=1;
ALTER TABLE `customer_entity_text` AUTO_INCREMENT=1;
ALTER TABLE `customer_entity_varchar` AUTO_INCREMENT=1;
ALTER TABLE `tag` AUTO_INCREMENT=1;
ALTER TABLE `tag_relation` AUTO_INCREMENT=1;
ALTER TABLE `tag_summary` AUTO_INCREMENT=1;
ALTER TABLE `tag_properties` AUTO_INCREMENT=1;
ALTER TABLE `wishlist` AUTO_INCREMENT=1;
ALTER TABLE `log_customer` AUTO_INCREMENT=1;
 
 
##############################
# ADDITIONAL LOGS
##############################
TRUNCATE `log_url`;
TRUNCATE `log_url_info`;
TRUNCATE `log_visitor`;
TRUNCATE `log_visitor_info`;
TRUNCATE `report_event`;
TRUNCATE `report_viewed_product_index`;
TRUNCATE `sendfriend_log`;
TRUNCATE `log_summary`;
 
ALTER TABLE `log_url` AUTO_INCREMENT=1;
ALTER TABLE `log_url_info` AUTO_INCREMENT=1;
ALTER TABLE `log_visitor` AUTO_INCREMENT=1;
ALTER TABLE `log_visitor_info` AUTO_INCREMENT=1;
ALTER TABLE `report_event` AUTO_INCREMENT=1;
ALTER TABLE `report_viewed_product_index` AUTO_INCREMENT=1;
ALTER TABLE `sendfriend_log` AUTO_INCREMENT=1;
ALTER TABLE `log_summary` AUTO_INCREMENT=1;
 
SET FOREIGN_KEY_CHECKS=1;

Magento dev site redirects to live site 1

When taking a copy of a production site and installing it on a dev server, you’ll need to do a few things for the application to load the dev server and not redirect to the live site.
1. Change the site_url entries in the core_config_data table to match your dev site’s url
2. Delete everything in the magentoroot/var directory
3. Update the app/etc/local.xml file to point at your local database
4. This is the one that usually stumps me for a bit… ensure the magentoroot/var directory’s permissions are opened up (777 the var directory). If this is not done, Magento will write your Magento temporary and cache to the system temp and you magically be redirected to the live site.