You can include a hidden field in the form, which will be SHA1Hash ("some-secret" + Remote_IP + PerSessionSecret).
PerSessionSecret is what you automatically generate at the start of a session. "some-secret" is a global secret value that will help a little if the randomly generated PerSessionSecret is not random enough.
Then do the same calculation when submitting the form, and you know that it is most likely sent from the same client to which it was sent. (Of course, if you have several clients behind a single address, such as a proxy or NAT, you cannot distinguish them reliably).
Andrew Y
source share