Saturday, December 30, 2006

PHP Form Signature

In my previous post, I began developing the concept of creating a checksum for a form to help prevent spammers from abusing forms on web sites. A malicious spammer will first attempt to inject code into a form in an effort to send e-mails through the web site's host. Those attempts can usually be foiled by properly validating the form fields. However, a spammer may still inject their marketing materials into a form that appears to send an e-mail to someone, not really caring where that e-mail might wind up. If these e-mails are directed at a server administrator or the customer support staff, they can get very annoying, even if they are otherwise rendered harmless by the validation rules. The goal then is to try to ensure that a given form post if from a human being, and not from a robot. Visual and verbal "captchas" can be used, but that tends to annoy the human visitor, which we don't want to do.

The idea of using a checksum and a form timeout is one way a web developer might attempt to prevent a spammer from writing bots against forms. I am expanding on the idea of the checksum and will now call it a signature. This example is in PHP, and will work as-is, but I certainly encourage you to make your own variations.

In my previous post, I developed an example with two hidden fields which were used to validate the form post. In this example I do two things: 1) combine the timestamp and the hash to create one "signature" field, and 2) encrypt the timestamp to make it less obvious. These measures should make it more difficult for a robot to spoof posts to your forms. Note that with any encryption and hash scheme, it is possible to break the code, but the objective here is to make it so arduous that the spammer would rather look elsewhere for targets than your forms. My opinion is that it would probably be easier for someone to hack the server than this form validation technique, so one must not overlook hardening the rest of the server, of course.

Since you might use this code in several places, consider making it an include:

include_once 'cryptography.php';

function formSignatureCreate($formPassword){
    $formTime = array_sum(explode(' ', microtime()));
    $encryptedTime = encrypt($formTime, $formPassword);
    $hash = formSignatureHash($formTime, $formPassword . $encryptedTime);
    return $hash . $encryptedTime;

function formSignatureValidate($formSignature, $formPassword){
    $encryptedTime = substr($formSignature, 32);
    $formTime = decrypt($encryptedTime, $formPassword);
    $hash = formSignatureHash($formTime, $formPassword . $encryptedTime);
    if(!is_numeric($formTime)) {
        return false;
    $currentTime = array_sum(explode(' ', microtime()));
    if($currentTime - $formTime > 1800) {
        return false;
    if($_SERVER['HTTP_USER_AGENT'] == ''){
        return false;   
    if($hash == substr($formSignature, 0, 32)) {
        return true;
    return false;

function formSignatureHash($formTime, $formPassword){
    return md5($formTime . $_SERVER['REMOTE_ADDR'] . $_SERVER['HTTP_USER_AGENT'] . $_SERVER['SERVER_NAME'] . $formPassword);

The encrypt and decrypt functions are wrappers I have placed around the rc4crypt code. You may use any encryption technique you want, of course, as I am only showing this as an example. These functions include a conversion of the encrypted string to base 64, so I do not have to deal with making the string web-friendly at this level.

For the time stamp ($formTime) , I have used the microtime() PHP function for simplicity, but you could use a formatted time as well, along with appropriate changes in the formSignatureValidate() function. This time stamp is encrypted with a password designated by the programmer. It is probably a best practice to have a unique password with each form, and since it is on the programming side, it can be a random sequence of characters.

The hash is generated in the formSignatureHash() function, which combines the following elements:

  • $formTime - The time the form was created, which allows us to validate that the form POST was submitted within a certain time frame.

  • REMOTE_ADDR - To tie the form post with the client's computer.

  • HTTP_USER_AGENT - To tie the form post with the client's browser.

  • SERVER_NAME - To tie the form to a given host server.

  • $formPassword - To tie the form POST to a given form.

Just to further confound any reverse-engineering, I combine the encrypted time with the given form password when the hash function is called.

Within the form, add a hidden field for the signature:

<? $signature = formSignatureCreate('thisFormPassword'); ?>
<input type="hidden" name="signature" value="<? print $signature; ?>" />

The way I have set this example up, a new signature would be created if other validation checks failed. This eliminates the need to validate the basic form (i.e., alpha-numeric) of the signature itself before printing it back into the form. We would not want someone attempting to inject code into an unvalidated signature variable!

In your validation section, add the signature check:

if(formSignatureValidate($signature, 'thisFormPassword')) {
    // other form validation
} else {
    // spawn error message

During validation, I make this my primary check. If the post does not pass the signature check, there is no reason to do any other validation, since it will always be rejected. In my error messaging system, I do not even display the input form again, forcing the visitor to click on a link to start the original form over. You may wish to restart a little more graciously with a blank form.

The formSignatureValidate() function first decrypts the time portion of the signature. In this example, the hash portion is always 32 characters long, so it is easy to pull the encrypted time off the end. Since I have used the microtime() function, it is easy to check to be sure the timestamp is 1) numeric and 2) within the 30 minute (1,800 second) time frame allowed.

I do an additional check on HTTP_USER_AGENT only because one of my sites was once attacked by a robot without a name. I don't bother checking during the signature creation phase, since it is really only important in the validation phase. If you know of specific rogue agents or IP addresses, those can be globally addressed in an .htaccess file or in the server configuration.

The final check is that the regenerated hash matches the hash at the beginning of the signature.

If all these checks pass, then it is considered a genuine post.

I have thought of a way to defeat this methodology. Someone could certainly develop a script to "screen scrape" the signature dynamically, but hopefully, a spammer will consider that too much effort. If the need arises, it is likely one could come up with a methodology to dynamically create the signature name as well. Time will tell. In the meantime, I hope this helps someone. I hope to develop a Java/JSP version of this in the near future.

Thursday, November 30, 2006

Thwarting form spammers in ColdFusion

As I have posted on before, spammers are more and more attempting to use form posting methods to send emails through unsuspecting web hosts. The most dangerous form, of course, are posts through which the spammer injects code that is run invisibly on the server. This approach can often be foiled by verifying form post data and properly escaping characters before they are displayed anywhere.

I have added validation to all the forms on the web site for the main company I work for, but one spammer is still attempting to use a form. However, the only destination is an administrative e-mail box, so the spammer has expended a lot of effort to effectively annoy only a few people. We have been receiving about 100 spam messages a day in the box, so further action was needed to stop this spammer and any other who might follow after.

One common solution has been the "captcha," a graphic with hard-to-read text that only the human brain can theoretically interpret and relay back to the server to prove the post did not originate from a robot. For our purposes, however, this approach is undesirable since it makes forms less usable. I wanted to come up with a verification process that is invisible to humans and would be (nearly?) impossible for a robot to reproduce.

My solution is to create a checksum value that would consist of data from the server, from the client, and from the form that could be matched up before and after the post to "prove" it to be authentic. Taking a page from our login guidelines, I thought it also appropriate to have forms time stamped, further hindering the likelihood that the checksum could be duplicated, and would certainly make it impossible for a "good" post to be reused at a later time.

This first solution is in ColdFusion since that is what this company uses the most right now. I plan to follow shortly with a PHP example followed by a Java/JSP example.

Creating the Checksum

The following code creates the checksum value. Any number of variables can be used to create the checksum, with the only requirement being that the values at the time of validation have to be the same as the time of posting.

This code uses the following four values:

  • dateTime - The time the form was created, which allows us to validate that the form POST was submitted within a certain time frame.

  • remoteAddress - The client machine's address, which allows us to validate that the form POST arrived from the same machine that requested the original form. Specifically, this would thwart spammers who use Trojans to hijack unprotected computers and make them spam zombies.

  • serverName - This is the web server's domain name in this example. If your servers are inside a firewall, and/or if you have multiple, load balanced servers with "sticky persistence" (i.e., a client is guaranteed to always communicate with one particular server during its session), you might use either the server's IP address or a global variable specific to a given server.

  • formName - On sites that I program, each form is given a unique name. Originally, this was for statistical usage purposes, but it can also come in handy here. This is essentially a "password" for the form data, preventing a given set of validation code from attempting to validate data from a different form.

Overall, this system attempt to guarantee that communication about one form is transferred between a known host and a known client within a known time span. Any detected violation prevents validation from proceeding. Hashing this data using a technique like MD5 creates a checksum that should be virtually impossible to reverse-engineer. Even though spammers are persistent, they are more likely to hack someone else's less protected site than tackle this problem.

<cfparam name="form.dateTime" default="#DateFormat(Now(),'yyyy-mm-dd')# #TimeFormat(Now(),'HH:mm:ss')#">
<cfset remoteAddress = cgi.REMOTE_ADDR>
<cfset serverName = cgi.SERVER_NAME>
<cfset formName = "formSomeName">
<cfset form.checksum = hash("#form.dateTime#~#formName#~#remoteAddress#~#serverName#")>

The next piece of code is added into the form. The only two pieces of information in clear text are the dateTime and checksum values (now that I think about it, these two values could actually be encrypted and given different names to further enhance security - I will most likely do that in further form work). All of the other variables live on the server, and the spammer would have to know all this, including your separators and the exact sequence of variables used, in order to forge the checksum value (not likely without inside help or an outright takeover of your server).

<input type="hidden" name="dateTime" value="#form.dateTime#" />

<input type="hidden" name="checksum" value="#form.checksum#" />

On the validation side, you want to add the following code at the top.

<cfif cgi.REQUEST_METHOD IS NOT "POST" OR NOT isDefined("form.checksum")>
    <cflocation url="/" addtoken="No">
<cfset remoteAddress = cgi.REMOTE_ADDR>
<cfset serverName = cgi.SERVER_NAME>
<cfset formName = "formSomeName">
<cfset checksumTest = hash("#form.dateTime#~#formName#~#remoteAddress#~#serverName#")>
<cfif checksumTest IS NOT form.checksum>
        <cfset errorMessage = "The form data was corrupted. We are sorry, but we cannot send your request at this time.">
<cfif isDate(form.dateTime)>
    <cfif checksumTest IS form.checksum AND DateDiff("n", form.dateTime, now()) GT 30>
        <cfset errorMessage = "The form data has expired. We are sorry, but we cannot send your request at this time.">
    <cfset errorMessage = "The form date was corrupted. We are sorry, but we cannot send your request at this time.">

If the errorMessages is set, you most likely want to halt further validation to prevent any harmful code from affecting anything you have missed validating. At this point you are already aware that something is amiss! This should not be your only line of defense, however. You still want to validate every field to make sure it contains data of the right datatype, length, and is free from characters that could lead to other hacks.

CSS hack to differentiate between IE 6 and 7

I discovered this quite by accident, and thought this might be helpful for those who find they need to set up different stylesheet rules for formatting in Internet Explorer 6 and IE 7. The crux of this solution is the CSS attribute selector (dentoned as square brackets [] in CSS). It turns out that IE6 does not understand attribute selectors, and, in fact, will ignore the entire associated rule (including rules with more than one selector).

To leverage this difference, two rules can be defined. A normal rule that will be rendered in IE6, and a duplicate rule containing an attribute selector that will be rendered in IE7. In the example below, I use the IE-specific "if" statement to show how you can further differentiate between IE and "other browsers." The solution below was tested in the Windows environment using IE6, IE7, Oprah 9, and Firefox 2.

If you use a different browser or environment, try the code out and let me know what you see.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "">
<html lang="en" xml:lang="en" xmlns="">
    <title>CSS hack to differentiate between IE 6 and 7</title>
    <meta name="author" content="John A. Marsh" />
    <meta name="copyright" content="&copy; 2006" />
    <style type="text/css">
        P {
    <!--[if IE]>
        <style type="text/css">
            P {
            P[],P {
    <p>Blue in IE 6, Red in IE 7, Green in non-IE browsers.</p>

Monday, October 30, 2006

JavaScript parent / child communication example

In a test I was running, I needed a valid date of birth in mm/dd/yyyy format. Here is the solution I came up with:

${__javaScript(with(new Date()) dob = String(Math.floor(Math.random() * 12) + 101).substr(1) + '/' + String(Math.floor(Math.random() * 28) + 101).substr(1) + '/' + String(getFullYear() - Math.floor(Math.random() * 99) - 1), dateString)}

The plain JavaScript version is

with(new Date()) dob = String(Math.floor(Math.random() * 12) + 101).substr(1) + '/' + String(Math.floor(Math.random() * 28) + 101).substr(1) + '/' + String(getFullYear() - Math.floor(Math.random() * 99) -1 ); alert(dob);

The first part gives us a zero padded month from 01-12. The second part gives a zero padded day from 01-28 (I did not want to deal with leap years and end-of month guessing for this test). The final part subtracts 1 to 100 from the current year (guaranteeing no future dates in the current year). Quick and dirty -- Enjoy!

Thursday, May 04, 2006

Struts Upgrade - Validation-rules.xml - Solution

At the company where I work, we are upgrading our WebSphere servers from version 5 to 6. In the process, we are also updating our Java applications. Part of the application upgrades involve converting from Struts 1.1 to 1.2.8.

I have spent two days puzzled by the problem this caused with form bean validation. I was getting errors like this:

[5/3/06 9:46:11:643 EDT] 00000057 DynaValidator E org.apache.struts.validator.DynaValidatorForm validate org.apache.struts.validator.FieldChecks.validateMask(java.lang.Object, org.apache.commons.validator.ValidatorAction, org.apache.commons.validator.Field, org.apache.struts.action.ActionErrors, javax.servlet.http.HttpServletRequest)
org.apache.commons.validator.ValidatorException: org.apache.struts.validator.FieldChecks.validateMask(java.lang.Object, org.apache.commons.validator.ValidatorAction, org.apache.commons.validator.Field, org.apache.struts.action.ActionErrors, javax.servlet.http.HttpServletRequest)
at org.apache.commons.validator.ValidatorAction.loadValidationMethod(
at org.apache.commons.validator.ValidatorAction.executeValidationMethod(
at org.apache.commons.validator.Field.validateForRule(
at org.apache.commons.validator.Field.validate(

The error message gives no indication of what the actual problem is, and while I found several posts on the Internet of people who have had the problem, I have not seen any solutions yet. My best clue was from an article in the Apache Wiki.

The root cause is that the validation method's signature has changed. Another issue is that the old ActionError method has been depricated and replaced with ActionMessages. Rules in your validation-rules.xml file should now look like this:

<validator name="required"

Hope that helps someone

Tuesday, April 25, 2006

Exporting Outlook Contacts Folders - Solution

A problem I have run across a couple of times, and have noticed that many others have is exporting Microsoft Outlook Contacts folders to a comma separated values (CSV) file. By default Outlook can only export one folder at a time. I have not found any software add-on yet that can do this either.

However, I have discovered by accident a way to do this using the Plaxo service. Plaxo comes as an optional install with the AOL Instant Messenger Triton application. I personally could not use Triton because it lacks Proxy settings or any way to change the communication port.

Anyway, when you use Plaxo, you can upload all your contacts to their web sites, and a fortunate side effect (depending on how seriously you take your privacy), it can help you discover your contacts' AIM addresses, and if they also are in Plaxo, will share whatever information the person allows to share.

One feature is that you can export your contact list. You are given the option to export all your contacts or any one folder of your choice. The download options are:

  • Microsoft Outlook (.CSV file)
  • Outlook Express (.CSV file)
  • Palm (.CSV file)
  • Netscape (.LDIF file)
  • Yahoo! (.CSV file)
  • vCard (.VCF file)

Hope this helps someone! Let me know if you have comments or questions. My main question is why can't Microsoft make this easier???

Wednesday, March 08, 2006

VBScript / Excel / SendKeys / Sleep - Solution

This is a script I wrote to help me add IPTC information to over 1200 images. It contains several techniques you might be able to use in your own VBScripts.

' Based on a script to automate Excel with VBscript by Richard L. Mueller
' Demonstrates several additional functions including
' 1) Launching applications
' 2) using SendKeys to control application
' 3) useing Sleep to pause execution during the script
' 4) Arrays

' I wrote this script to help me update the IPTC data of images
' I had downloaded the data from MySQL and put it in an Excel spreadsheet
' Each line of the spreadsheet contains the file name and the desired IPTC information
' I leverage IrfanView to insert the IPTC information into each photograph
' This IPTC information is later read by the server using PHP when I upload the pictures to my photography web site

' You have a royalty-free right to use, modify, reproduce, and
' distribute this script file in any way you find useful, provided that
' you agree that the copyright owner above has no warranty, obligations,
' or liability for such use.

Option Explicit

Dim objExcel, strExcelPath, objSheet, intRow
dim fileName, pictureTitle, pictureDescription, keywords, categoryID, thisYear, originalDate, filesys

' Bind to Excel object.
On Error Resume Next
Set objExcel = CreateObject("Excel.Application")
If Err.Number <> 0 Then
On Error GoTo 0
WScript.Echo "Excel application not found."
End If
On Error GoTo 0

strExcelPath = "C:\Temp\originals\tblPictures.xls"

' Open specified spreadsheet and select the first worksheet.
objExcel.WorkBooks.Open strExcelPath
Set objSheet = objExcel.ActiveWorkbook.Worksheets(1)

dim category(9)
category(1) = "Plants"
category(2) = "Animals"
category(3) = "Landscapes"
category(4) = "Textures"
category(5) = "Structures"
category(6) = "Miscellaneous"
category(7) = "John"
category(8) = "People"
category(9) = "Transportation"

dim WshShell
Set WshShell = WScript.CreateObject("WScript.Shell")
Set filesys = CreateObject("Scripting.FileSystemObject")

'Get copyright symbol - VBScript does not have a way to do an alt-0169 combination

Dim charMap
charMap = WshShell.Run("CharMap")
WScript.Sleep 250
WshShell.AppActivate charMap
WScript.Sleep 250
WshShell.SendKeys "{TAB}{TAB}{RIGHT 3}{DOWN 5}~"
WScript.Sleep 250
WshShell.SendKeys "%F"
WScript.Sleep 250
WshShell.SendKeys "Times New Roman"
WScript.Sleep 250
WshShell.SendKeys "%C"
WScript.Sleep 250
WshShell.SendKeys "%{F4}"

' Iterate through the rows of the spreadsheet after the first, until the
' first blank entry in the first column. For each row, bind to the user
' specified in the first column and set attributes.
intRow = 2
Do While objSheet.Cells(intRow, 1).Value <> ""
    originalDate = Mid(objSheet.Cells(intRow, 1).Value, 4, 8)
    fileName = "C:\Temp\originals\" & objSheet.Cells(intRow, 1).Value
    if filesys.FileExists(fileName) Then
        pictureTitle = objSheet.Cells(intRow, 2).Value
        categoryID = objSheet.Cells(intRow, 3).Value
        pictureDescription = objSheet.Cells(intRow, 4).Value
        keywords = objSheet.Cells(intRow, 5).Value
        ' On Error Resume Next
        thisYear = mid(originalDate, 1, 4)
        WshShell.Run ("C:\Programs\Graphics\I-View\i_view32.exe " & fileName)
        WScript.Sleep 250
        WshShell.AppActivate "IrfanView"
        WshShell.SendKeys "i", True
        WScript.Sleep 250
        WshShell.SendKeys "%i", True
        WScript.Sleep 250
        WshShell.SendKeys "^v " & thisYear & " John A. Marsh, all rights reserved" & "{TAB}", True
        WshShell.SendKeys replace(replace(pictureDescription, "(", "{(}"), ")", "{)}") & "{TAB}John A. Marsh{TAB}", True
        WshShell.SendKeys pictureTitle & "{TAB}", True
        WScript.Sleep 250
        'WshShell.SendKeys frmOptions.infoInstructions.Text, True
        WshShell.SendKeys "^{TAB}" & keywords, True
        WScript.Sleep 250
        WshShell.SendKeys "^{TAB}" & category(categoryID), True
        WScript.Sleep 250
        WshShell.SendKeys "^{TAB}John A. Marsh{TAB}Photographer / Owner{TAB}John A. Marsh{TAB}", True
        WScript.Sleep 250
        WshShell.SendKeys "^{TAB}" & pictureTitle, True
        WScript.Sleep 250
        WshShell.SendKeys "{TAB}", True
        WshShell.SendKeys thisYear & "{TAB}" & Mid(originalDate, 5, 2) & "{TAB}" & Mid(originalDate, 7, 2) & "{TAB}{TAB}", True
        WScript.Sleep 250
        WshShell.SendKeys "Durham{TAB}North Carolina, NC{TAB}United States of America, USA{TAB}", True
        WshShell.SendKeys "{ENTER}", True
        WScript.Sleep 250
        WshShell.SendKeys "%o", True
        WScript.Sleep 250
        WshShell.SendKeys "%{F4}"
        WScript.Sleep 250
    end if
    intRow = intRow + 1

' Close workbook and quit Excel.

' Clean up.
Set objExcel = Nothing
Set objSheet = Nothing

WScript.Echo "Done"

Sub IrfanviewIPTC(fileName)

'Add IPTC data to image via SendKeys commands to IrfanView

'start application
'Dim appIrfanView
'appIrfanView = Shell("C:\Programs\Graphics\I-View\i_view32.exe " & fileName)

End Sub

Tuesday, February 21, 2006

JMeter Birthday Boundary Testing - Solution

One of the applications I was testing today required a boundary test for people aged 65 years old. To do this, I set up two variables, one with a generated date exactly 65 years ago, and the other being 65 years old plus one day, thus giving an age of 64.


${__javaScript(with(new Date()) X = String(getMonth() + 101).substr(1) + "/" + String(getDate() + 101).substr(1) + "/" + String(getFullYear() - 65), dateString)}


${__javaScript(with(new Date()) X = String(getMonth() + 101).substr(1) + "/" + String(getDate() + 100).substr(1) + "/" + String(getFullYear() - 65), dateString)}

Note that this will fail on the last day of the month and the day before a leap day. But hey, you have been working hard all month ... take a day or two off! ;-)

Wednesday, February 15, 2006

Formatted Date in JMeter / JavaScript - Solution 2

In another JMeter testing scenario, I wanted to set a user defined variable to a date string with the format "yyyymmddhhmmss". The solution below solved the problem of left-padding with zeros and getting all the formatting done in a single line.

${__javaScript(with(new Date()) X = getFullYear() + String(getMonth() + 101).substr(1) + String(getDate() + 100).substr(1) + String(getHours() + 100).substr(1) + String(getMinutes() + 100).substr(1) + String(getSeconds() + 100).substr(1), dateString)}

The uses of this kind of user variable include:

  1. Knowing exactly when a test was run for auditing

  2. Guaranteeing a unique string for things like new test usernames [note that I am writing regression tests which only run once. If you are running load tests, you will want to add String(getMilliseconds() + 1000).substr(1) to get unique string each pass]

  3. Having a string you can key off of, for example to clean up database entries you have made

Sunday, February 05, 2006

Boxes With Rounded Corners in CSS - Solution


CSS Code

.textBox {
    background:#9cf url(/images/question-box.gif) left top no-repeat;
    /* Width attribute needed to fix behavior in Internet Explorer */
    /* width:100%; */
.textBox .right {
    background:url(/images/question-box-right.gif) right top no-repeat;
.textBox .bottom {
    background:url(/images/question-box-bottom.gif) left bottom no-repeat;
.textBox .corner {
    background:url(/images/question-box-corner.gif) right bottom no-repeat;


<div class="textBox"><div class="right"><div class="bottom"><div class="corner">
    <p>It is easy to create a resizable box with rounded corners using Cascading Style Sheets (CSS). Four nested &lt;div&gt; elements are required, each having a background image respectively set to the left-top corner (including the body), right edge, bottom edge, and right-bottom corner.</p>

See screenshots at , along with some examples of why the workaround is necessary in Internet Exploer 6 and 7. My question: Why don't they fix that? If less funded browser companies like Firefox and Opera have come up with solutions, why can't Microsoft?

Formatted Date in JMeter / JavaScript - Solution

I am using JMeter for regression testing, and needed a way to use the current date in mm/dd/yyyy format in a form post. Here is the solution I came up with using the JavaScript function:

${__javaScript(d = new Date; prefix=d.getMonth()<9?'0':'';X = prefix + String(d.getMonth()+1) + '/' + d.getDate() + '/' + d.getFullYear(), Dummy)}

Looks like date formatting in JavaScript is a perpetual problem, so I hope this is helpful.

Microsoft Word Clears the Clipboard - Solution

I had been using Microsoft Word for years, when suddenly I had a strange problem where if I copied text to the clipboard, then opened Word, and then attempted to paste that nothing would happen OMG!. I have searched on the Web serveral times, but have not found a solution until now. Turns out I needed to disable a COM addin.

Thanks to Dopyiii ( for getting me on the right track.

His instructions for viewing COM addins:

  1. Open Word and go to Tools > Customize > Commands tab
  2. In the Categories section on the left, choose Tools
  3. In the Commands column on the right, you'll see "COM Addins"
  4. Grab this COM Addins button and drag it up and drop it off on your toolbar somewhere.

    • It doesn't matter where - you'll delete it in a minute anyway.

    • The quick way to delete this button (or to customize the toolbar) is to hold down Alt and click and drag the button into the document. When you let go, it'll disappear!

  5. Close the Customize dialog
  6. Now, click the new COM Addins button on your toolbar.

    • Like the Templates and Addins dialog, you can enable or disable whatever you see here

    • Remove the button if you like, or keep it there for nostalgic purposes.

I found that when I disabled Natural Voice Reader, I was able to paste after opening. Most people won't have NVR installed, of course, but this might also get you on the right track if it is a COM addin that is causing the problem. Let me know if this helps you!

Spammers can exploit unvalidated PHP forms

This is a message I sent to the AOL postmaster on September 19, 2005:

I have recently figured out that an AOL member known as "homerragtime" has developed a method to exploit unvalidated form posts to send SPAM e-mail. For several months homerragtime was successful sending e-mail through my unvalidated forms, and I was perplexed at receiving so many rejected spams that appeared to have come from my own site.

About two months ago I finally began validating my forms, and began to find form postings like the following being captured by my validation process:

send Content-Type: multipart/mixed; boundary=\"===============1010877498==\" MIME-Version: 1.0 Subject: 90c4558b To: bcc: From: This is a multi-part message in MIME format. --===============1010877498== Content-Type: text/plain; charset=\"us-ascii\" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit wygqm --===============1010877498==--

The tip-off for me was seeing the BCC field. It appears homerragtime has a robot that crawls the web and posts these kinds of messages. If he gets one of the messages that he is BCCed on, he matches that with the number in his subject line, and then knows that the form can be exploited. I did a search for homerragtime, and see this same signature in many places.

Please research this further. I believe homerragtime is violating your company policy not to send spam, even though technically, he is sending the spam through other people's web sites.

A few more notes:

  • I have found this problem has occurred on all three of the web sites I maintain. They are all fixed now.
  • My sites are all in PHP, but it is quite possible that this exploit could be used in other languages.
  • Bottom line: validate your forms. This person was very aggressive at sending out spam through my sites, judging by the large number of rejected e-mails I was getting returned to me.

IE Toolbar Names Get Mixed Up

I enjoy adding toolbars to Internet Explorer (currently have nine). I do not keep them all active all the time, of course. I only keep the Google toolbar open all the time and open others as needed. However, I have noticed a problem where when I right click on the toolbar area to open or close a toolbar, the names do not always correspond to the correct toolbar. For example, clicking on Yahoo! may open or close Google. Sometimes this can get very confusing when, say, four toolbars have switched names .

Anyone else seen this? I have not seen it documented on the Web, and I have not figured out a solution yet.

Wednesday, February 01, 2006

Formatted Date in JMeter / JavaScript - Solution

I am using JMeter for regression testing, and needed a way to use the current date in mm/dd/yyyy format in a form post. Here is the solution I came up with using the JavaScript function:

${__javaScript(d = new Date; prefix=d.getMonth()<9?'0':'';X = prefix + String(d.getMonth()+1) + '/' + d.getDate() + '/' + d.getFullYear(), Dummy)}

Looks like date formatting in JavaScript is a perpetual problem, so I hope this is helpful.