Site Network: Personal | Professional | Photography

Technical Blog

This blog will contain content related to Java, Seam, Security, my sites and projects, as well as other technical subjects I am interested in.

Comments and questions are welcome!

Archive for the ‘Security’ Category

AT&T DNS Cache Poisoning

Thursday, July 31st, 2008

Recently there has been a lot of press about AT&T DNS servers being hit with a DNS Cache Poisoning attack.

Some new easier exploits were recently published, and many DNS servers are still vulnerable. And up until the new exploits were published publicly, the majority of DNS servers were vulnerable. This situation is worse once you realize that "safe" DNS servers can be poisoned second hand by transitive trust relationships, allowing one compromised DNS server to effectually poison the caches of other un-compromised DNS servers.

DNS Cache Poisoning has been a serious issue for years. The recent flurry of press regarding the compromised AT&T DNS servers is just the tip of the iceberg. It is only reasonable to assume that over the past several years a large number of DNS server have been serving compromised results at some point, either by direct poisoning or indirect poisoning. It is also reasonable to assume that this will continue for the foreseeable future.

In light of this, please re-read my post on 3rd party Javascript.

If I were a malicious hacker, let's say working for the Russian Mob, or for myself, here is the easiest way to make some money:

1. Create javascript files designed to mask Google Adwords, Google Analytics, Doubleclick Ads, Overture Ads, and maybe a couple others. These scripts would have their cache related response headers set to be cached on the browser for 1 year. These scripts would call back to the real versions of themselves (so that ads show up, etc...). They would also intercept any form submission events and would look for form fields with names like "creditcard" or "ssn" or "password" or "accountnumber", etc... If any are found, it would essentially clone the form and send the form data, the site hostname and page, the client's IP address and cookies, etc... to a server I control.

2. Start cache poisoning as many DNS servers as I could find that are vulnerable to point the REAL domains for those scripts to my malicious copies.

3. Sit back and watch the Credit Card numbers roll in.

The best part is that by getting the browser to cache the script locally, I only have to have a computer hit the poisoned cache once to control it for a whole year. On most IE6 installations it's also easy to actually install a javascript application on the user's computer.

Personally I use Google javascripts on my site. However I don't capture credit card numbers here, so the risk is low. If you run an e-commerce site, please do not underestimate the risks involved here.

JForum SSO (single sign-on) and Atlassian Crowd

Sunday, June 8th, 2008

Over at our new ATG Developer Community site, we're using Atlassian Crowd to manage our user accounts, groups, and single sign-on (SSO) between Jira, Confluence, to manage Subversion authentication, and to handle the forums (JForum) user accounts.

There was an example on how to integrate JForum and Crowd, which works pretty well. When you login to the forum, it checks Crowd and creates a local account if needed and logs you in.

However, we want single sign-on (SSO) so that our users don't need to login to the forums separately. We also want group membership in Crowd to be reflected in JForum to allow us to manage permissions based on Crowd managed groups.

I've written a JForum SSO implementation that ties into Crowd that I'm going to share here. It's version 1.1 (just added group sync), but it seems to work nicely.

Download the zip file here:
jforum-crowd-sso

unzip it into your jforum/WEB-INF/classes/ directory.

You have to install the crowd client jar, and the crowd.properties file.

You may also need to install the xfire jars if you get errors. I did.

Then you need to setup the sso configuration in the jforum/WEB-INF/config/SystemGlobals.properties

like this:

authentication.type=sso
sso.implementation = com.digitalsanctuary.jforum.CrowdSSO
sso.redirect = your crowd managed app login page
sso.crowd.syncGroups=false

That last flag should be set to true if you would like the user's groups synced from Crowd to JForum at auth time. This takes a second, so I made it optional. It does not push JForum group membership info to Crowd, it just syncs Crowd data down, as Crowd should be your master directory for that type of data.

The source code is available here for now:

CrowdSSO.java

-EDIT-

Added a full downloadable module and installation instructions here:

http://confluence.atlassian.com/display/CROWDEXT/JForum+Single+Sign-On+Crowd+Connector

Using IPTables to Prevent SSH Brute Force Attacks

Saturday, May 24th, 2008

If you have a server with a world facing ssh server, you've probably seen brute force attacks in your logs. Some machine starts hammering your ssh server, trying all sorts of logins (staff, root, a, admin, etc...) over and over and over again.

This is bad on a lot of fronts.

I use two simple iptables rules to block any IP address who has made more than 3 ssh connections or attempted connections within the past 3 minutes. So your would-be brute force attacker, gets three tries, and then is locked out for a minimum of three minutes. However, since 99% of the attacks are run by an automated bot, it will either: give up after the connection is refused multiple times, or it will keep hammering away on the closed door, which keeps the running count of attempted connections in the past 3 minutes over 3, keeping the door closed.

First:

iptables -I INPUT -i eth1 -p tcp -m tcp --dport 22 -m state --state NEW -m recent --set --name DEFAULT --rsource

Then run:

iptables -I INPUT -i eth1 -p tcp -m tcp --dport 22 -m state --state NEW -m recent --update --seconds 180 --hitcount 4 --name DEFAULT --rsource -j DROP

I'd also recommend using the script in my post on blocking IP addresses using iptables to deal with any persistent folks, or people poking too hard on your web site, or other services.

Getting the Real IP Address from a Proxied Request in ATG

Tuesday, April 8th, 2008

Many things can obscure the real IP address of the end user when they visit your site: a load balancer in front of your ATG cluster, Akamai, the user's ISP or office network, and more. This makes correlating logging events, or using the ATG session IP validation security option, and more, very difficult. In light of that challange I've added a new mini-module to my Open Source ATG Modules called the ProxyIPFixer. It uses a simple ATG pipeline Servlet to examine the X-FORWARDED-FOR request header, and if it finds one, parse through the IP addresses to find the originating IP address of the user, and puts that value into the ATG Request object's remoteAddr property.

This allows downstream pipeline servlets, code, and pages to see the real user's IP address.

The caveat is that the header can be faked, and that some ISPs/companies, such as AOL, do not set the true end point of the user, and you can only see back to their outgoing proxy server. In AOL's case in particular, they can also route subsequent requests by the same AOL user through different AOL proxy points, which will make it appear that someone is hijacking a session (if you're using the ATG session security mechanism). So be aware of the limitations. However it can be very useful.

For those who don't want to download the whole module package, I have attached the Java source and the ATG properties file to this post.

Enjoy! (and as always feel free to contact me with questions, issues, improvements, etc...)

ProxyIPFixerServlet Java Source

ProxyIPFixer ATG Properties File

login-required=”true” Will End Your Conversation

Monday, March 10th, 2008

In Seam, in the pages.xml or mypage.page.xml files, you note that a given page requires the user to be logged in to view the page. It is a very easy way of handling simple security. What happens is if a user attempts to access a page with the login-required="true" attribute and they are not logged in, they are automatically redirected to your login page (as defined in your pages.xml). Once they login, they are automatically redirected back to the page they had attempted to access initially. Very elegant, and much easier than writing all that yourself.

There is however a "gotcha" you should be aware of in this flow. If you use the login page, or logic, to start a long running conversation (I do this because my User entity object has some large binary properties which I want lazily loaded), the post-login redirection will kill that conversation. In my case this led to lazy loading exceptions down the road.

It took me a while to figure out the cause, as it only happened much later in the application, and most of the time it worked (when I logged in purposefully from the main page), but sometimes would break (when I'd had an expired session and gone through the login auto-redirection flow). Eventually though I was able to track it down to those two scenarios.

What is happening is this: before the first redirection happens (to the login page), the Seam Redirect classes captureCurrentView method is called. This basically saves the information about the page you were trying to view (it's a little more complex than that- being all Faces like and whatnot, but that's the gist of it). This method creates a long running conversation in order to hold this state across the multiple pages. If there was no previous long running conversation to join, and it had to create a new conversation, it stores a conversationBegun flag of true.

Then you hit the login page, where the page (or code) would Begin a long running conversation, except you almost certainly have join=true, so it joins the existing long running conversation, which was created by the captureCurrentView method. This is the conversation your User entity was loaded up in.

After your login was successful, the Redirect classes returnToCapturedView method is called to send you back to where you'd tried to go initially.

This method has the following block:

 
if (conversationBegun) {
       Conversation.instance().end();
}
 

This ends the conversation you had loaded your User entity within, and when you hit your destination page, there is no long running conversation at all. Then, a few minutes later, it's lazy loading exception time.

The downside is there isn't a really clean fix that I am aware of yet.

The upside is there is a pretty simple hack: just add a <begin-conversation join="true" /> to all of your pages which have the login-required="true" attribute. This creates a new long running conversation before the Redirect does it's work, so it in turn joins that conversation instead of creating a new one, the conversationBegun flag is false, and the returnToCapturedView method doesn't end your conversation. It's a hack, and you have to remember to add it to every page which requires a logged in state, but it does work.