Online Payment Solution for RoR Application: PayPal - Security

...continued from IPN Implementation.


Further, for security reasons you can use authentication certificates by following step given below:
  1. Create a directory named as 'certs' to accommodate certificates and generate RSA (certificates). Set expiry time etc, it will ask for some details on your console, fill required details.
mkdir certs
cd certs
openssl genrsa -out app_key.pem 1024
openssl req -new -key app_key.pem -x509 -days 365 -out app_cert.pem
  1. Now you have two files in certs directory. Login Merchant's Account -> Profile -> My Settings -> Encrypted Payment Settings -> Add -> browse and select app_cert.pem file -> Add.
  1. Now you can see a column 'Cert ID' ,copy and paste (in some text file) the text under this column, its your paypal certificate id. We will use it in further steps.
  1. Select the added certificate (using radio buttton) and click Download button. Use following command to move downloaded file from your downloads directory to application's certs directory.
$ mv ~/Downloads/paypal_cert_pem.txt paypal_cert.pem

In paypal_url method of app/models/product.rb, add
:cert_id => AppConfig.cert_id,

after
:notify_url => notify_url,

and replace
:business => YOUR_MERCHANT_EMAIL

with
:business => AppConfig.paypal_email

and then replace
"https://www.sandbox.paypal.com/cgi-bin/webscr?" + values.to_query

with
encrypt_for_paypal(values)
  1. Add following code into your model to encrypt your information:
PAYPAL_CERT_PEM = File.read("#{Rails.root}/certs/paypal_cert.pem")
APP_CERT_PEM = File.read("#{Rails.root}/certs/app_cert.pem")
APP_KEY_PEM = File.read("#{Rails.root}/certs/app_key.pem")

# openssl encryption.
def encrypt_for_paypal(values)
signed = OpenSSL::PKCS7::sign(OpenSSL::X509::Certificate.new(APP_CERT_PEM), OpenSSL::PKey::RSA.new(APP_KEY_PEM, ''), values.map { |k, v| "#{k}=#{v}" }.join("\n"), [], OpenSSL::PKCS7::BINARY)

OpenSSL::PKCS7::encrypt([OpenSSL::X509::Certificate.new(PAYPAL_CERT_PEM)], signed.to_der, OpenSSL::Cipher::Cipher::new("DES3"), OpenSSL::PKCS7::BINARY).to_s.gsub("\n", "")
end

  1. Create a file named as 'config.yml' in config/ directory for storing different values for different environment. Add following code carefully.
development:
paypal_url: "https://www.sandbox.paypal.com/cgi-bin/webscr"
paypal_email: YOUR_MERCHANT_EMAIL
cert_id: PAYPAL_CERT_ID

production:
paypal_url: "https://www.paypal.com/cgi-bin/webscr"
paypal_email: YOUR_MERCHANT_EMAIL
cert_id: PAYPAL_CERT_ID

Note: PAYPAL_CERT_ID is what you saved in step 21.
  1. In app/views/products/index.html.erb, replace
<%= link_to 'Buy Now!!', product.paypal_url(products_url, notification_products), :class => "btn primary"%>

with
<%= form_tag AppConfig.paypal_url do %>
<%= hidden_field_tag :cmd, "_s-xclick" %>
<%= hidden_field_tag :encrypted, product.paypal_url(products_url, notification_products_url) %>
<p><%= submit_tag "Buy Now!!", :class => "btn primary"%></p>
<% end %>
  1. Login to merchant account -> Profile -> Website Payment Preferences -> Select 'ON' radio button under heading 'Encrypted Website Payments' -> Save.

It will block non-encrypted websites to make payments.

Thats It!!! Enjoy!



Troubleshooting:

  • uninitialized constant AppConfig
Open config/application.rb and add require 'ostruct' before start of module and following code in the module:

# Load settings from the application settings file.
settings = YAML.load_file("#{Rails.root.to_s}/config/config.yml")
app_config = settings['common'] || {}
app_config.update(settings[Rails.env] || {})
::AppConfig = OpenStruct.new(app_config)

The fully implemented application is uploaded on heroku: PayPal Integration.

You can checkout application's code here.

Go Back to IPN Implementation.

Comments

  1. Good to know that it helped even after years I wrote this.

    ReplyDelete

Post a Comment