Web Programming, Linux System Administation, and Entrepreneurship in Athens Georgia

Author: Brandon (Page 19 of 29)

Use ProxyPassReverseCookieDomain with to maintain Tomcat sessions through mod_proxy_ajp

I had a customer today who had problems using Tomcat sessions after configuring his application to run through mod_proxy_ajp. Everything worked correctly when hitting the application correctly on port 8080, but any attempts to hit the site through Apache and mod_proxy_ajp would result in the sessions not being saved, and a new session being created on every request.

The problem is that Tomcat is sending a Set-Cookie header with the Path that it knows about – which is different than what the browser is requesting.

The application is at https://www.mydomain.com/, and mod_proxy_ajp is redirecting that to https://localhost:8009/myapp/.

Here is the HTTP Response Headers that Tomcat is sending

HTTP/1.1 200 OK
Date: Sun, 28 Oct 2007 01:39:44 GMT
Set-Cookie: JSESSIONID=TOMCAT_SESSION_ID_HERE; Path=/myapp
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 11234
Connection: close

You can see in the Set-Cookie header that it is setting a cookie path of /myapp. The browser receives this and will only send that cookie back on requests sent for requests beginning with /myapp. Fortunately Apache 2.2 includes the ProxyPassReverseCookiePath directive to rewrite the Set-Cookie headers on these requests. You can configure a virtual host like this:

<VirtualHost *:80>
    ServerName www.realdomain.com
    ProxyRequests Off
    ProxyPass / ajp://127.0.0.1:8009/myapp/
    ProxyPassReverse / ajp://127.0.0.1:8009/myapp/
    ProxyPassReverseCookiePath /myapp /
</VirtualHost>

And now the HTTP Response headers look like this:

HTTP/1.1 200 OK
Date: Sun, 28 Oct 2007 01:39:44 GMT
Set-Cookie: JSESSIONID=TOMCAT_SESSION_ID_HERE; Path=/
Content-Type: text/html;charset=ISO-8859-1
Content-Length: 11234
Connection: close

The browser now sees that the cookie is for / and will send the JSESSIONID cookie for all requests to this server.

Block comment spam with bcSpamBlock

A while ago I installed Paul Butler’s JSSpamBlock on my WordPress blog here. His original idea is simple and brilliant: Spambots don’t (yet) execute Javascript. In fact, they usually post directly to the form without even displaying the form first. By having a hidden input field that is populated by javascript, you can verify that users are hitting the page without the user even noticing. For users with JavaScript disabled (are there any of you out there), they simply have to copy/paste a small string into a textbox for verification.

Since implementing a slightly modified version of it on this blog, I have gotten zero spam posts. Now, I wanted some way to implement the same logic on some of my own custom PHP sites to prevent spam on them as well.

While working on a way to re-implement Paul’s WordPress plugin in my own sites, I came up with something pretty clever. Instead of saving a row to a database every time that the form is displayed, you can use a little cryptography to make the client pass all of the data needed to validate the request back to you on its own. The idea is sortof merger between the JSSpamBlock plugin and TCP Syncookies, which use a similar method of having the client store the data for you.

Essentially, how it works, is that the function generates a Random ID. It then encrypts the current timestamp and the random ID using PHP’s crypt() function with some cryptographic salt that is unique to each server. All three of those values (the random ID, the timestamp, and the encrypted value) are then passed to the browser. The timestamp and the encrypted value are stored in hidden <input> fields, while the random ID displayed for the user to verification. If the user has JavaScript enabled, a few lines of JavaScript copy the random ID into another textbox, and then hide that prompt, so that it is never seen by the user. If the user doesn’t have JavaScript enabled, the would have to copy/paste that random ID into the textbox themselves, similar to a captcha.

When the form is submitted, it checks to make sure that the timestamp is not too old, and then re-encrypts the passed in timestamp and random ID using the same salt value to make sure it matches the crypted value passed in from the form. If everything matches, the comment is approved, otherwise an error is displayed to the user.

I wrote this up into a simple include file that can be used for any PHP application. I also implemented a quick WordPress plugin that uses the generic version. More information about it can be found on my new bcSpamBlock home page

Update 2024-10-01:

There are much better spam blocking plugins now, so this has been discontinued.

Get your Dell Service Tag number via the Linux command-line

When your server is located in a data center far away, it makes it difficult to walk over to the box and read the service tag off of it. Fortunately, the Service Tag is stored somewhere in the system BIOS, and is accessible with the ‘dmidecode’ utility.

[root@host ~]# dmidecode|grep "Serial Number"
                Serial Number: 80NZV71

You’ll probably see several other serial numbers in there as well for things like your hard drives or other devices. The Dell shouldn’t be too difficult to pick out. I think they are always 7 digits and have letters in middle. There is lots of other interesting things in the ‘dmidecode’ output too, like the speed and type of each RAM module installed, and a description of all of the onboard devices (ie: video and network cards)

With Windows

Thanks to @kleinbaas who commented below how to do the same thing on a Windows machine:

  C:\Documents and Settings\brandon>wmic bios get serialnumber
  SerialNumber
  GX245D1

Fix for CentOS “Can’t do setuid (cannot exec sperl)”

If you are running a Perl script with the setuid bit, it actually runs a slightly modified version of Perl so that it is a bit more cautious. On a CentOS box, you need to install the ‘perl-suidperl’ package to get the necessary files installed. Otherwise you get an error like this:

[root@host bin]# ls -al myscript.pl
-rws--S--- 1 mail mail 1218 Oct  1 13:09 myscript.pl

[root@host bin]# ./myscript.pl
Can't do setuid (cannot exec sperl)

Check DomainKeys, DKIM, SPF valiadity, and SpamAssassin score in one place

I spent the whole day today stepping through DomainKeys, DKIM, and SPF for a customer to make sure that they were all set up and working properly. I found a couple of the existing tools available on the Internet didn’t test them properly and didn’t give enough explanation when they failed.

So, I went about creating some of my own tests using a bunch of Perl modules. I finally fixed a couple issues that I think were causing problems for this customer. Gmail and Yahoo are now delivering the messages anyway. Hotmail is still a mystery (no surprise since its from Microsoft). Their troubleshooting website is full of talk about how great their service is, but there is a huge lack of anything technical on the site.

Anyway, I made all of these nifty testers and figured that others might like to use them. So I created a way for others to send mail to it, and a web interface that you can view all of them results. I’ve added it as a link to the top of my website.

Perl Mail::DomainKeys module doesn’t verify gmail messages

I was trying to verify a DomainKeys message from gmail with the Perl Mail::DomainKeys module and it wouldn’t verify for some reason.  After digging into the module a bit, I found that gmail doesn’t send the ‘q=’ parameter to specify the method to look up the public key.  Obviously this should default to ‘dns’ since it is the only currently supported method.

I modified Signature.pm and added this to line 56:

$self->{‘PROT’} = $self->{‘PROT’} || ‘dns’;

And now the messages are verified properly.  I’ve emailed the module’s author about it, but am not sure if he’ll bother with releasing a fix.  DomainKeys is being dropped in favor of DKIM.

DomainKeys and DKIM step-by-step verification

I spent a good part of the day today working to make sure that a DomainKeys and DKIM server was properly signing messages. Here’s some of the confusing stuff I sorted out:

First off DomainKeys and DKIM are different slightly different technologies that do the same thing. My understanding is that Yahoo, Gmail, and others came up with DomainKeys as a solution to to solve email forgery. The EITF then tweaked the original DomainKeys spec a little and made their version called DKIM (DomainKeys Identified Mail). The two are very similar and I haven’t found anything that describes their technical differences.

First, I guess it helps to know basically how DomainKeys works. Essentially the administrator creates a Public/Private key pair on the mail server. The private key is used to sign the message while the public key is posted as a DNS TXT record for receiving mail servers to use for verification. Receiving mail servers then use the public key from DNS to decrypt the signature and make sure that the signed headers and message body were not modified in transit. I’ll describe DomainKeys here, and just understand that DKIM might implement things slightly differently.

The DomainKeys spec is available here
The DKIM spec is available here

Note that this doesn’t actually do any spam checking on its own. It simply verifies that the message came from an who it claims and wasn’t tampered with along the way. It is intended to be used for fighting phishing, and creating a reliable reputation-based services.

Originating mail server:

When a message is submitted to a mail server for signing, it uses the ‘From’, and ‘Sender’ headers, as well as the message body, in combination with the Private Key to generate a DomainKeys signature. This signature is added to the rest of the email headers and looks something like this:

DomainKey-Signature: a=rsa-sha1; s=mail; d=somedomain.com; c=simple; q=dns;
	b=PcrSGNIF8mZFBLPCz3UD5Na901YOAgWgHT5La7O799bnYkbDcqnpawVjB0fAcZQSb
	qxZk4iE5utyhaTij0NmS4tPx5qJHMzw3fwJKWXqV+7H5kyP8LkMRNLBDnzk9Om+

You’ll notice that the header contains several name=value pairs that describe things about the signature. Here are some important options that may be used in the Signature:

a= describes the hash algorithm used to create the key (usually rsa-sha1)
s= contains the selector (described later).
d= the domain to use for signing
q= the method for retrieving the public key (only dns is currently supported)
p= the base64 encoded signature
See section 3.3 in the DomainKeys specs for more details or Section 3.5 in the DKIM spec

After the MTA adds these headers, it forwards the message as normal to the recipient.

The receiving mail server can then perform some validation on messages that it receives which contain a DomainKey-Signature header. To do that the receiving MTA receives the message.

For every message (regardless of weather or not it has a DomainKeys-Signature header) it receives, it looks up the DomainKeys policy record for the senders domain. This is a text record with the name ‘_domainkey.DOMAINNAME.TLD’ where the ‘_domainkey’ part of that is always ‘_domainkey’. If the message does have a DomainKeys-Signature header, the -d parameter should match the domain portion of the ‘From’ header.

The policy record for a domain has these options:
Section 3.6.2 in the DomainKeys spec and 7.4 in DKIM specs
Of interest include:
o= can be either a hyphen (-) to indicate that the domain signs all email (and non-signed messages can be treated as invalid) or a tilde (~) to indicate that the domain signs some messages.
t= Set this to ‘y’ to indicate that you are testing. Receiving mail servers are not supposed to penalize you if the message does not verify and the ‘t’ flag is on.

A Policy record for ‘somedomain’ might look like this:

[root@host ~]# dig +short -ttxt _domainkey.somedomain.com
"t=y; o=~; [email protected]"

(not that the ‘dig’ application is adding quotes around the record and adding backslashes before the semicolons.) the actual record in my DNS server looks like this:

t=y; o=~; [email protected]

You can use the DomainKeys Policy Record Checker to verify that your policy record is in an acceptable format.

Next, for messages that have a DomainKeys-Signature header, it uses the s= flag which describes the selector to create a DNS TXT query for

<selector>._domainkey.<domain>.<tld>. It will look something like this:

[root@host ~]# dig +short -ttxt mail._domainkey.domain.com
"k=rsa; p=MHwwDQYJKoZI...a bunch of characters removed for formatting...UAfbN8pL/f6YwIDAQAB"

Of interest here are these options:
k= The key type (always ‘rsa’ for now)
g= (dkim only) used to limit the addresses that a public key can be used for. For instance to outsource some email without giving the third party permission to sign any address.
n= human-readable notes (not to be used for anything)

You can use the DomainKeys Selector Record Tester to verify that your selector is set up properly

After the receiving mail server has retrieved these records, it can decrypt the DomainKey-Signature header and verify that the message is authentic.

For end-to-end verification that everything works, there are a couple of testers available at Skylist (for DKIM and DomainKeys) and Deliverability.com
A few email auto-replies are also available the DomainKeys page

Google before it was google

I’m not sure how I stumbled on it, but I came across this really old version of the BackRub home page – which is what evolved into Google. Its kind of interesting to see that some of the links that work and see some of the things that they mention.

I particularly enjoy the note to ‘ignore cgi-bin errors’ and that performance is slow due to NFS and antiquated hardware

Also, in the description of their logo in the FAQ is funny:

“The logo is simply a scan of my hand, from a flatbed scanner converted to black and white. The “back” in the picture is the scanner cover, and the shadows are from the scanner light.”

BackRub logo

Cisco prefix-list to strip default route from received BGP routes

In playing with some routing last night, I needed to filter the default route that we received from the BGP announcements from our peers. I didn’t find exactly what I was looking for via Google, so I began experimenting. After a dozen or so unsuccessful changes, I came up with this that actually accomplishes what I was trying to do:

ip prefix-list NO_DEFAULT_ROUTE seq 1 deny 0.0.0.0/0
ip prefix-list NO_DEFAULT_ROUTE seq 2 permit 0.0.0.0/0 ge 1 le 24

Then apply that to a BGP session with something like this in your BGP configuration

 neighbor 10.20.30.40 prefix-list NO_DEFAULT_ROUTE in

Although that did accomplish that goal of filtering out the default route, it turns out it still didn’t do what I wanted. Oh well. Having a static default route is probably a bad idea anyway.

Saving money on Domain Registrations

I have something like 30 domain names that I own, so I’m always looking for a way to save a few bucks on registrations.   GoDaddy.com always has some special offer for a percentage off, or reduced prices.   I used to keep all of their emails so that I could go back through them when I needed to buy something.  I just came across this site that displays all of the currently active and recently expired coupons.  Now I can unsubscribe to their newsletter and keep it from filling up my inbox.

Also, I stumbled on the ‘bulk pricing‘ on godaddy’s site.   When renewing 6+ domain names at a time, you can get a discount as well.  Over 20 domains and the prices are about the same as with discount codes.

« Older posts Newer posts »

© 2025 Brandon Checketts

Theme by Anders NorenUp ↑