#143 PayPal Security
This episode shows how to encrypt the variables passed to PayPal and verify the authenticity of the payment notifications (IPN).
- Download:
- source codeProject Files in Zip (103 KB)
- mp4Full Size H.264 Video (21.2 MB)
- m4vSmaller H.264 Video (13.3 MB)
- webmFull Size VP8 Video (23 MB)
- ogvFull Size Theora Video (28.3 MB)
Resources
- Episode 141: PayPal Basics
- Episode 142: PayPal Notifications
- Episode 85: YAML Configuration File
- Nifty Generators
- Full Episode Source Code
bash
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 mv ~/Downloads/paypal_cert_pem.txt paypal_cert.pem script/generate nifty_config
models/cart.rb
def paypal_encrypted(return_url, notify_url) values = { :business => APP_CONFIG[:paypal_email], :cmd => '_cart', :upload => 1, :return => return_url, :invoice => id, :notify_url => notify_url, :cert_id => APP_CONFIG[:paypal_cert_id] } line_items.each_with_index do |item, index| values.merge!({ "amount_#{index+1}" => item.unit_price, "item_name_#{index+1}" => item.product.name, "item_number_#{index+1}" => item.id, "quantity_#{index+1}" => item.quantity }) end encrypt_for_paypal(values) end 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") 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
models/payment_notification.rb
def mark_cart_as_purchased if status == "Completed" && params[:secret] == APP_CONFIG[:paypal_secret] && params[:receiver_email] == APP_CONFIG[:paypal_email] && params[:mc_gross] == cart.total_price.to_s && params[:mc_currency] == "USD" cart.update_attribute(:purchased_at, Time.now) end end
carts/show.html.erb
<% form_tag APP_CONFIG[:paypal_url] do %> <%= hidden_field_tag :cmd, "_s-xclick" %> <%= hidden_field_tag :encrypted, @cart.paypal_encrypted(products_url, payment_notifications_url(:secret => APP_CONFIG[:paypal_secret])) %> <p><%= submit_tag "Checkout" %></p> <% end %>
app_config.yml
development: paypal_email: seller_1229899173_biz@railscasts.com paypal_secret: foobar paypal_cert_id: WKKX2FSCFDB8C paypal_url: "https://www.sandbox.paypal.com/cgi-bin/webscr" test: paypal_email: test@example.com paypal_secret: testsecret paypal_cert_id: 123456789 paypal_url: testpaypalurl production: paypal_email: foo@example.com paypal_secret: supersecret paypal_cert_id: KLHZSK326HEDS paypal_url: "https://www.paypal.com/cgi-bin/webscr"