by Christof Wollenhaupt, Foxpert
Login, Logout, Knock out
Microsoft has a lot of experience and knowledge in developing secure applications and actually does so. What sounds like a failed attempt to be funny, is surprisingly true. Microsoft spent hundred of millions dollars in the research of security, has got worldwide recognized security experts and is permanently challenged by tens of thousands of security experts and its competition.
This makes it even more surprising that most developers start from the ground with the security aspects of their own applications. Hence, it's obvious that security is not the primary focus of software developers. Without hesitation, they demand administrator privileges for their application and implement their own login dialog to restrict access. They write their own encryption routines to encrypt single field in a table. They spend a lot of effort to protect tables in case of power failures.
For all these problems there are readily available solutions that are – almost with certainty - superior to the homemade solutions. Using the login dialog and password check I'd like to show how many security leaks a Visual FoxPro application could have. Technically, such a login dialog is very simple. The user enters user name and password. The application executes a query. Execution continues if user name and password are valid. Otherwise the application terminates, usually after a few unsuccessful attempts.
That's the theory. In reality, though, there's a lot that can go wrong. Let's start with some particularities of Visual FoxPro. In the following samples I assume that the user name is stored in lcUser and the password in lcPassword. A typical password validation could look like this:
* ASSUME: We located the correct record in USER.DBF
IF NOT ALLTRIM(User.cPassword) == m.lcPassword
* invalid password
* password is OK
That looks pretty safe, doesn't it? However, what happens if lcPassword is NULL? Every expression that contains NULL is NULL itself. A condition that is NULL cannot be true, never. If an IF condition results in NULL, Visual FoxPro always executes the ELSE branch. In the sample above, the user can log on successfully, if he only knows a correct user name. In the password textbox all he needs to do is to hit CTRL+0, and Visual FoxPro assigns NULL to the Value property of the textbox. This way it's quite easy to log on as an Administrator.
Check every IF command if the condition can be NULL
The sample above is only dangerous if the attacker knows a valid user name. Otherwise, he wouldn't make it beyond the SEEK like that I omitted in the sample. Unfortunately, user names are often easy to guess. It's particular easy for a stranger to guess a user name if he doesn't have to enter them, but can comfortably pick one from a combobox. If then – as demonstrated in the VFP Tastrade sample – a picture of each employee is included, no one should be surprised if passwords or other information are quickly discovered and harm is done. In Windows XP or MSN Messenger, all possible login names are even clearly listed, as well. Since Microsoft's designs have always been copied in the past it's just a matter of time to see similar login dialogs in other applications, too.
Comparing strings in Visual FoxPro is everything but a simple topic. If two strings are considered to be equal depends on a number of factors. These are SET EXACT, SET NEAR, SET COLLATE, SET ANSI, as well as various codepage related settings. Take a look at the following sample and find out how to bypass the validation routine:
* ASSUME: We located the correct record in USER.DBF
lcPassword = NVL(m.lcPassword,"") && live and learn...
IF ALLTRIM(User.cPassword) = m.lcPassword
* invalid password
* password is OK
And, have you been successful? Instead of using the == operator, the code above uses the = operator. This operator respects the current SET EXACT setting. The default is OFF which means that the left-hand string is only compared up to the length of the right-hand string. The expression always returns .T. if the value on the right side is an empty string. Logging on successfully is just a matter of not entering any password, at all!
Check all string operations for unwanted side effects, especially =, <=, <, >, =>, #, != and <>.
Up to now we only focused on the actual string comparison. But what about the User.DBF table itself? Maybe we can open the table outside the application. If the password is stored in clear text, you don't need any further explanations. Mostly, the password is encrypted before it's stored in a table. Surprisingly, only two algorithms cover most such encryptions. Either, the password is XORed with a secret key, or the ASCII value each character in the password is incremented or decremented by a fixed or variable value.
XOR is a very popular encryption mechanism. If you XOR a string with a secret key, you get an encrypted text. If you XOR the encrypted text with the secret key, you get back the original string. But if you XOR the original string with the encrypted text, you get… the secret key. Whoops. The addition/subtraction tricks, too, are easy to find, especially if the same differences are used for all passwords. All you need is a pair of encrypted and plain passwords. Those don't even have to be valid.
To get at them is often easier than necessary. If user data is stored in a SQL server, an application typically uses an ODBC query to verify the password. If the query returns a record, the password was correct. If, on the other hand, there's no match for the password and user name entered, the password was wrong. That means, on the client side, the password is encrypted and the assembled SELECT statement is sent to the server using SQLEXEC() or REQUERY(). In other words, the encrypted password is sent across the network without further protection. An ODBC Trace Tool or a Network Monitor can easily reveal them.
With local data the opposite approach might be possible. To make it easier the application might copy the user table into a cursor and decrypt it. All accesses go to the cursor instead of the table. That's secure as long as Visual FoxPro has enough memory. If that ceases to be the case, Visual FoxPro starts swapping cursors to disk as .TMP files. You can analyze these files to your heart's content, if you kill VFP in the task manager or turn off the computer abnormally. Nonetheless, there are much easier approaches for Visual FoxPro based data that are discussed later in this article.
The problem is the same in all cases: The encrypted password is stored in the table. The solution cannot be to encrypt the password even better. The solution must be not to save the password in the first place! But how to validate a password if it's not stored somewhere? Think about what you actually want to accomplish. The content of the password doesn't matter, at all. All you want to know is if the entered password matches the stored value. For that, you don't need the password itself; a place holder is just as good.
Such a place holder is called a hash. A hash algorithm converts a string of arbitrary length into a single number that is most likely different for different input strings. We all know such functions for checksum calculations. The Windows CryptAPI provides functions to obtain such hash values using very secure algorithms. To make it easier to use this API, Visual FoxPro contains a class library named _CRYPTAPI.VCX since version 7. To validate the password you compare the hash value of the entered password against the stored hash value in the user table. Even if an attacker has both values, he can not conclude from those of other passwords. Better, even if he knows the algorithm that was used to obtain the password, that's of no use. To obtain a password for a known hash, he would have to invert the algorithm. Most hash algorithms are asymmetric, though. While it's easy to obtain a hash value, you need to calculate the hash value for any possible password to get the opposite. This method is called a brute force attack, and is usually the last resort as it is takes a very, very long time. For good algorithms on today's computers this can be millions of billion years. On the other hand, brute force attacks have a 100% chance of success… if you have enough time.
Never store secret information, just place holders.
That's not only true for data, but also for the contents of the memory. If there's an error in an application, Visual FoxPro makes it extremely easy to collect information about the current state and environment. You cannot only get the line number and error code, but information about every aspect of Visual FoxPro using
LIST STATUS | MEMORY | OBJECT | CONNECTIONS | DLLS
Such information are often stored in error logs. You can really make a hacker happy if you store the password of the user in a variable. He only has to wade through the LIST MEMORY logs to find a considerable number of passwords with no effort at all. That's even true if you only store the password temporarily in a procedure. It's much harder to cause an error just in this moment, but often this is possible by deleting an index tag or a file.
Unencrypted system information do not belong into an error log.
In general, deleting of files is one possibility to gain access to a system. In cases of an error, many applications pick a default value that is comfortable to the developer or user, but hardly secure. Suppose, you have the following function to obtain the return value of a modal VCX form:
loForm = CREATEOBJECT(tcForm)
uRetVal = loForm.uRetVal
And call this function from the main program like this
llLoginOK = CallModalVCX("frmLogin")
In your tests, this function works flawlessly every time. But, what happens if there's an error while loading the form? If you, for instance, bind a textbox to a table and that table doesn't exist, Visual FoxPro doesn't create the form at all. In the code above, loForm would be .F. in the first line and cause errors in the next two lines. Hence, uRetVal would never be defined and the RETURN line would fail, too. Visual FoxPro always returns a value from a function and a procedure. If you don't provide Visual FoxPro with a value, Visual FoxPro uses its default value: .T. Since .T. is also the return value for a successful login, the user can login by renaming a file.
Error handling is always critical. In case of an error you should always think carefully about which options a user may have. Ignoring an error can be an option during development, but not at runtime. You should always cancel the current function. That means, either terminate the application immediately, or use RETURN TO or TRY…CATCH at the READ EVENTS to continue execution at a predetermined point. If you log the error, you shouldn't store information that aren't absolutely necessary. If you have the possibility and need these data, better encrypt error logs.
Don't let the user continue program execution in case of an error.
Admittedly, causing an error to bypass a security check can be called an advanced technique. So far, we focused on comparing the value. But locating the record, too, could cause security issues. One variation of causing an error is
While SEEK can search NULL values, this is only true if the indexed field also allows NULL values. Otherwise, SEEK cancels out with an error. If that error is ignored, the record pointer is still on the first record and the password validated. The hacker therefore doesn't have to know the name of the user. Since typically the first record contains a test user for the developer or the administrator, there're good chances that this attack results in using a privileged account.
More and more applications, though, do not save data in FoxPro tables, but in a SQL server database. To send a query to the SQL server, the application assembles SQL statements and often sends them with SQL Pass-Through to the SQL server. The following code tries to determine, if the password is correct. How long do you need to crack the following code?
lcSQL = "SELECT * FROM User WHERE cUsername='"+;
NVL(m.lcUser,"")+"' AND nHash="+TRANSFORM(NVL(lnHash,0))
IF SQLEXEC(lnHandle,m.lcSQL)>0 and RECCOUNT("SQLResult")>0
The password query has been replaced through a hash value query, but the user name is still inserted into the query unchanged. That allows the hacker to modify the query as he wishes, for instance, when he enters the following user name:
' or 1=1 or 1=1
The resulting query always returns records. Additionally, the code checks if the SQL server returns records at all. The correct verification would be to check if exactly one record is returned. Multiple records in the result set would mean that there are multiple records for the same user and the same password. Such a constellation should have been prevented by the database. The possibilities are not limited to altering a simple query. Depending on the backend you can send multiple commands in a single command string. A hacker could create new users, change passwords and execute stored procedure in one pass from the login dialog.
Always validate user input before using it any further.
Another tendency of developers plays an important role in security. Most SQL servers have a very powerful user right management system. For each table and each column you can specify if a user can read or write to it. You can specify if records can be deleted or added. You can precisely define who can alter the database, like adding a new table, adding a stored procedure, adding or deleteing users, and so forth.
In reality, though, these features are hardly used. Typically all users of the application share a common user account that has been created for the application. This user often has got the rights that the administrator of the application - or even the developer - needs. Sometimes, developers even use the sysadmin account provided by the SQL server. Often, such a configuration doesn't seem to be a problem as the application controls access and only the developer and the system administrator know the password. Let me rephrase this for you: The only protection of the database is the login dialog of the application. You have seen on the last few pages how little security that could mean. If the user can control the SQL server right from the login dialog, it might be the safest solution to drop that dialog completely.
Use the security mechanisms that you server offers.
Similar problems do not only exist with SQLEXEC(). In Visual FoxPro, too, there are many possibilities to shoot oneself into the foot: macro substitution, EVALUATE() and SCRIPTEXEC(). If input values are used in conjunction with these features without further validation, a hacker has the entire arsenal of Visual FoxPro at his hands. As we will see later, you only need a single point in the application to execute code to turn off most conventional security mechanisms.
All input values have to be validated if they are in an acceptable form. The most important rule is to strip off all terminating characters. In Visual FoxPro this is the quotation mark, the single quotation mark, and square brackets that are used as string delimiters. With HTML these are mostly "<" and ">" which you should remove from the input stream. In FoxPro you can easily use the CHRTRAN() function for that. For security reasons, you should focus on valid characters and remove all others:
The inner CHRTRAN removes all valid characters. The remaining characters are invalid. The outer CHRTRAN uses this string to remove invalid characters from the original string.
In the previous chapter you have learned how easy it is to bypass many security mechanisms in many Visual FoxPro applications. Someone attacking my application? Impossible! You are right, if you think of terrorist activities, evil former employees or prestige-addicted script kiddies. In reality, though, the much smaller dimensions are those that are a risk to your application.
That could be a competitor who wants to learn about the inner workings of your application or, purely, wants to perform a data conversion for one of your former customers. If the core of your application is the database that you provided, your client might want to use that data in a different way than he is allowed to. When using address databases for mail merge letters, such a user could try to avoid the cost associated with every address he uses. Or, you have a colleague who believes to be smarter than you and feels forced to prove that. The worst group, however, is called the "power user". When the possibilities of the application are not sufficient, this group of users tries to user alternative applications to modify data, typically using Excel or Access. Upon saving you quickly end up with invalid values or memo fields that are truncated to 254 characters. Of course, no body did anything.
The frequency with which developers ask in online forums for encryption tools for application and data proofs a steadily increasing need for security. The increasing consciousness of security issues becomes an issue especially for independent consultants. More and more customers want to know how secure an application is and even let developers sign that somehow. If a developer signs such a paper believing in the security of tools like Refox or Cryptor, and there is an attack, this at least weakens the own position, or can be very expensive at max.
More over, there's a trend to distributed applications even in the FoxPro universe. This trend is not as far as many papers from Microsoft want to make us believe, but at least the integration of the internet is widely a fact, already. An automatic update via FTP or sending an email in case of an error doesn't sound like an unreasonable request of customers, anymore. For internal applications used by bigger companies another common request is to access the application with a browser via the intranet. The reason is usually a strategic decision of the management, even though technically such a solution might not make sense. Increasingly, SQL server is discovered and accepted as a more reliable data storage for Visual FoxPro applications.
The most common security mechanisms in Visual FoxPro applications try to protect against an external attack. To secure data developers often use an encryption library. There are two fundamental approaches to data encryption in Visual FoxPro: file and field based encryption. With the field based encryption, the program encrypts the content before each write access. Reading is done the opposite way: The content of the field is passed to a decryption function. Such a field can only be indexed on the encrypted contents. Creating an index on the decryption function would put the clear text of the protected fields into the CDX file where they can be recovered easily. Due to this restriction, you can only search for exact matches on encrypted fields. Searching on anything else involves the decryption function and disables Rushmore.
File based encryption doesn't suffer from this restriction. Depending on your needs you have multiple possibilities. If you want to prevent unauthorized users from reading data, the easiest solution is the Encryption File System (EFS). Such a file system comes with Windows 2000 and Windows XP. To enable it, set the file attribute "encrypted" in the file properties dialog. You access the file like before, because encryption works transparently. The application only sees decrypted data, on the hard disk there are only encrypted files.
If more than the current user should access these files, for instance, across a network you must have a Domain Controller. The Domain Controller manages the keys used for encryption. Windows EFS uses the DES algorithm. Depending on the Windows version, this is 40 Bit DES, 56 Bit DES, DESX or 3DES. The last one is currently considered to be quite safe and is the same used in bank transactions and ATM machines across Europe.
EFS is a good solution for internal applications running on the company network. Activating EFS is not a developer, rather an administrative decision and can be performed independently of the application. The administrator, and not the developer, controls file access rights. Those without access cannot read any data, even if they steal the hard disk and use NTFS file systems for DOS, or similar low-level tools. To read data, you need the keys that are stored on the Domain Controller. On that machine, the keys only become available when the hacker knows the administrator password. Decryption of these files therefore requires the computer with the desired data, the domain controller and access as an administrator. Nothing is perfectly secure, though. Since 2003 there are tools available that use a brute force attack in a reasonable time frame if part of the password is known.
If you need to protect data in a peer-to-peer network or you want to encrypt files before sending them to your users, there's only one tool available for FoxPro: Cryptor from XiTech. When Windows loads a DLL it creates a list of all functions and their addresses in memory. For each DLL there's such a jump list. Cryptor works by altering these jump lists. For instance, the function at index #224 in NTDLL.DLL is the NtReadFile() function that is used to read files. Cryptor has its own version of NtReadFile. In the list it changes the address at position 224 to point to its own version and saves the old address in some list. When now Visual FoxPro calls the NtReadFile function, it takes the function pointer at position 224 and calls Cryptor this way. Cryptor, on the other hand, calls the original function, decrypts all data and returns them to Visual FoxPro.
Calling the function is therefore entirely transparently and works for all utilities that run in the VFP process including third-party libraries and ActiveX controls. The disadvantage is that Cryptor has to be updated for each version of Windows. If Microsoft implements a new file access function, Cryptor has to implement it, as well. Otherwise, some functions would return decrypted, some encrypted contents. Should that happen at a write access, the file would be lost for ever. A further disadvantage of these tools is that Cryptor has to modify the jump list of DLLs. There are tools designed to prevent exactly this, because they either use the same trick, or because this behavior is typical for bad programs like viruses or worms. For instance, as of writing this, Cryptor does not work together with KonXise, even though both are from the same company. Additionally, Cryptor has to be loaded into its own process. This is the case when you launch an EXE. When creating a DLL you have to live with potential restrictions, though.
When protecting the application the goal is usually to prevent that someone can decompile the application and recover the sources. All products that don't produce machine code, but so-called P-code are especially vulnerable for de-compilation. If names like class names, method names, etc. are stored in clear text, because they are used to resolve dependencies, there are usually very good chances to restore the sources completely. There's a difference if the restored code reads
_1 = _2 * _3
lnSum = tnAmount * tnPrice
RETURN lnSum * Tax.Rate
Products like Visual FoxPro, Java and .NET are especially vulnerable for this kind of de-compilation. The approaches to protect applications are different in these products. In FoxPro the most common approaches are branding and encryption. In .NET the mostly used technique is obfuscation. That means that all variables, methods, etc. are renamed so that they don't make any sense. Obfuscators try specifically to reuse names as much as possible. In the sample above, "_1" was used in four different places: as a procedure name, a variable, an alias and a field name. Additionally, obfuscators alter the code in a way that it does the same, but doesn't look anymore like the code produced by the compiler.
The first approach in FoxPro was branding. That means that a brander writes a specific tag into the compiled file, like a password hash, for instance (yes, the manufacturers, too, know now to save passwords). When the same tool is used to decompile a program, this tag is checked and eventually the tool refuses to decompile the code. It's important to understand that it is the responsibility of the decompiler to respect this tag. Because the only thing changed in the program is this tag, Visual FoxPro doesn't notice this modification and can execute the application as usual. Here's a list of de-compilation tools for FoxPro:
If you use a different decompiler, you can de-compile an application without problems that has been branded by other tools. For complete protection you would have to brand your application with all tools. In the past when only few of such tools existed, that was not a big issue, but today developers in many countries around the world have been created decompilers that ignore other tags. Via the internet these tools are now available to all developers worldwide. Additionally, you can find patches on the internet that remove these tags. To find them simply search Google for "Refox" in combination with words like "warez", "crack" or "hack". Most pages are Russian or in various Asian languages, though.
Contemporary protection tools therefore encrypt the compiled EXE. An application treated in this manner is not recognized by Visual FoxPro anymore. In addition it's therefore necessary to add a loader program that decrypts the application and then calls the Visual FoxPro runtime. This technique is used by tools like ReFox with Level II, KonXise or Armadillo. A lot of new tools are currently under development or just out in their first releases. Differences among the tools are if decryption happens in memory or into a file, if the file is additionally compressed, and so on. The basic principle doesn't change, though.
Even though there are cracks for these tools and hacker constantly try to bypass their protection or to hack their encryption algorithm, all of these tools do their job quite well. However, just because one part is working you shouldn't expect that your application is secure. All these tools have one thing in common: they protect the application or data against external access. The Visual FoxPro application typically doesn't notice it is protected. Visual FoxPro can read files encrypted with Cryptor and execute application protected with KonXise.
All of these tools do not protect against attacks from the inside. The most successful strategy for internal attacks can be summarized as Code Injection meaning that code is executed inside the application. Visual FoxPro is extremely vulnerable for this kind of manipulation
Let me make some legal remarks. Decompilation and modification of executable files is prohibited by the license agreement of most products. Additionally, most countries have laws that make decompilation illegal even if such a clause is missing from the license agreement. In Europe there are only few legal exceptions for decompilation without the permission of the intellectual property owner. Should you need to decompile or modify (patch) an application, you should, in any case, contact the owner of the rights of this application and, eventually, a lawyer specialized in this subject. The following explanations are meant to give you an idea of what others could do with your code and to enable you to protect against that.
Code injection means that external code is executed inside the application. That doesn't have to be a negative thing, though. A Debugger in Windows, for example, loads one of its own DLLs into the debugged application to control the flow of execution in that process. How the external code gets into the application differs.
If a FoxPro application uses a FLL to encrypt data, it's quite easy to bypass this. The FLL has to exist physically on the disk for FoxPro being able to load it. In contrast to their counterparts in DOS, the PLB libraries, FLLs cannot be included into the application and loaded from their. In most cases the FLL remains on disk and is therefore easy to manipulate. The same applies to DLL in all Windows applications. In a Windows application you could write your own DLL that provides the same functions as the original DLL. Then you could capture all function calls and forward them to the actual DLL. Creating such a DLL can be automated if the interface definition is available. Now you are in the position to capture passwords passed on to that DLL, save them and use them later as needed. To protect against such a manipulation, you should create a checksum of FLL and DLL files, for instance, using the MD5 hash algorithm. Before loading a library verify the current checksum against one embedded in your application.
In Visual FoxPro you don't have to work that hard. When calling a function Visual FoxPro searches in the current program, in procedure files, in FLLs, in API declarations, in stored procedures, as external EXEs or APPs, or external FXP's. The exact search order varies between different versions of FoxPro. In any case, though, Visual FoxPro executes a FXP in the current directory when it didn't find any other procedure of that name anywhere else. Hence, if you change function names in a FLL and at the same time provide an FXP with that name in the current directory of the application, then the FXP is loaded and executed.
You don't have to be that clever to get at secret data. Imagine you had encrypted all tables with a tool like Cryptor. With an external attack the user has virtually no chance of decrypting these data if you picked a good password. Inside the application, however, you give the password to Cryptor. Visual FoxPro can then read all registered files without limitation. Developers tend to use the same password for all tables which is, moreover, stored inside the application somewhere. Because of its support of file masks, usually all tables are registered at once. The only remaining protection is therefore that only approved user get into the application. You might remember from the first chapter what the probability of this is like. If all tables are registered and not those only to which the current user has access to, you only need minimal rights to have access to all data.
Sufficient is including the report designer. If a user can modify reports in an application, he can open the data environment of the report and add any arbitrary table. The report designer offers even more surprises. Not only can you open tables on the disk. In the file open dialog you may enter any name of an included table that will then be opened in read-only mode. That might be useless for regular tables.
Class libraries and forms are nothing but tables. If you know the name of a class library, you can open it in the report designer. You find that name typically in the error messages. That's another reason to encrypt error logs and to not to display more than absolutely necessary. Even if you encrypted your application with any of the available protection tools this still works. The VCX in the report designer is decrypted and unprotected (how else should VFP be able to execute it).
There are many possibilities to execute code in your Visual FoxPro application. For instance, a user could write FoxPro code into a text file and then enter the following expression in the report designer:
In Visual FoxPro 6.0 and earlier this requires to create an FXP, but that's not really an issue. The report designer is really unreliable. Therefore either leave it out or isolate the designer into a separate application that is launched with RUN. If the report designer isn't available, what can you do to inject code into the application? The next easiest way is to run the application in the development environment. Put SET STEP ON onto an ON KEY LABEL to suspend the application at any time. If the application is encrypted this isn't an option as Visual FoxPro won't recognize the EXE as a Visual FoxPro application in the IDE. What we are looking for are ways to execute code that is not included into the EXE. If you can't imagine such a way here are some examples:
_STARTUP or COMMAND line in the config.FPW
Index expressions in tables
Field validation rules
External forms, classes, queries or programs
All kind of scripts that are executed by the application
Macro substitution, EXECSCRIPT(), EVALUATE() or name expressions that are not validated.
Some options are not available in all versions or the runtime libraries. For instance, the COMMAND line is ignored in the runtime version of the more recent Visual FoxPro versions. One trick, though, works almost every time. A free table used by the application is added to a database. Depending on the version of Visual FoxPro that you are using, you can now use trigger, validation rules and database events in that new database to add your own code. If you open a table in Visual FoxPro that is part of a database and you haven't opened the database yet, then Visual FoxPro kindly opens the database for you. If database events are enabled Visual FoxPro triggers the DBC_OpenData event before even the table is opened. This event can contain arbitrary code that, for instance, copies all tables into unencrypted files onto a huge removable disk.
If plain tables are insecure, OK, let's use SQL server. That secures data and your code is safe, anyway, you might think. Unfortunately, that's wrong. All class libraries, that is, VCX files, are tables. When loading a class Visual FoxPro opens them in the system data session. If you manage to execute code in the system data session, there's nothing that stops you from copying all loaded VCX files. While accessing the system data session (#0) sounds impossible at first, it's actually not a big issue. When evaluating an index expression, a field validation rule or a trigger, Visual FoxPro always activates the correct work area. Such a work area is always in a data session. All you need is a trigger in a table that Visual FoxPro opens in the system data session. As soon as Visual FoxPro starts making changes to that table, it executes the trigger code in the system data session.
The following program uses this trick to automatically copy all loaded VCX files onto the hard disk. In contrast to FXP files you cannot encrypt VCX files. Therefore they can not be protected by branding tools. VCXes extracted this way are entirely unprotected and can be decompiled by any decompiler available on the market. If you compiled the application with debug information that is not even necessary as the entire source code is still contained in the VCX! That's true even if you used any available encryption tool that can't be cracked externally.
It's very important to notice that this is not a problem with these products. They work as advertised. The reason is simply that the code below exploits a design in Visual FoxPro against which those tools were never designed to protect. These tools prevent decompilation from the outside. For technical reasons they can't do anything against code injection. There's no way for them to distinguish good code from bad code as far as security is concerned.
* Monitor the system datasession for loaded VCX libraries
* and save them to disk.
If Version(2) == 2
* Create an empty Resource file in a new database
Set Safety off
lnSelect = Select()
Create Database ExtractVCX
USE Sys(2005) Again
Copy Structure to ExtractVCX Database ExtractVCX
* Add a trigger to the resource file
Create Trigger On ExtractVCX For Insert as ExtrVCX()
Create Trigger On ExtractVCX For Update as ExtrVCX()
Create Trigger On ExtractVCX For Delete as ExtrVCX()
Set Resource to ExtractVCX
If Set("DataSession") == 0
Local laTables, lnTable, lnSelect
lnSelect = Select()
For lnTable=1 to AUsed(laTables)
If JustExt(Dbf()) == "VCX"
If not File("__"+JustFname(Dbf()))
? "Extracting: "+JustFname(Dbf())
Copy To ("__"+JustFname(Dbf()))
If you can modify the database, you could put this code into the DBC_OpenData event. The EXTRVCX function is called by a trigger. The trigger gets called on any write access to the resource file. That happens, for instance, when you close a report preview or a BROWSE window. Since most applications use a report designer, bets are good for you. Terminating an application, too, writes to the resource file. You might have to move EXTRVCX to a different location in this case, though, as the database might have been closed already.
Maybe the previous pages left you with a minor bad feeling, as most applications have at least one of these security leaks. Don't panic! Analyze the situation of your application and you might find out that there's not much of a problem, or lots of reasons to panic NOW! This analysis doesn't have to be a professional security risk analysis if you don't work in a security relevant area. As a starter it's often sufficient to think about the various aspects of security. The most common reason for security risks in applications is not the stupidity of the developer. They simply exist because nobody has thought about them. The most important questions for you to ask are:
Who could be interested in getting at my code or data?
Who has got the possibility to do that?
What abilities and knowledge do these persons have?
With the first question you find those that have an interest in attacking your application. The second question covers those that have (even a theoretically) possibility to do so. If you have a web shop, everyone with internet access could potentially break into your computer, but only a limited group, like the competitor, actually has an interest in specifically hacking into your application. This is an important difference, because FoxPro is more a niche product, and maybe even your application. That makes it much less probable that there are tools for automated attacks that Script Kiddies might use. On the one side this means that you less likely get into a broad attack in which you just happen to be the victim by chance. On the other hand it means that each attack is most likely targeted at you specifically. A hacker needs to have a certain amount of knowledge about FoxPro to compromise your application. That's different for ASP.NET applications running on IIS, for instance. Security leaks in that configuration spread quickly and tools are created that use them automatically. To attack a computer that is vulnerable to this attack you don't need to know how the attack works, just where to get the programs to perform the attack.
In most cases it's sufficient to protect the application against decompilation using ReFox or similar tools, to encrypt data files and to ensure that the LogIn dialog is really secure. That protects against the curious persons who simply have to try if the application can be decompiled or files be modified in Excel. A professional hacker won't stop that, but without these measurements your application would be completely unprotected. So even if ReFox might not protect against all types of attack, it's wrong not to use ReFox or a similar tool.
The big question is: how paranoid you should get? No matter what you do, there's a way round it. It's only a matter of time and effort. On the other hand, security measurements often lead to inconveniences for the honest user. And security costs money. Before you start protecting your application in many months' of work, you should clarify how much security is needed. For security issues the same is true as for all design issues. The early in the life cycle you start thinking about it, the cheaper it is. Try to achieve secure habits. Most solutions, like removing invalid characters from a string, take only minutes or less if you apply them right from the beginning.
Once you have figured out against whom you need to protect and how effort you want to spend on that, you could go through the following list of solutions. This list is neither complete, nor are these solutions fail-safe.
The rule, the most important rule, is: Avoid any access from the outside. For the code this means to use branding and encryption tools. For data this means to control access. Encrypt data if you cannot trust the administrator. Work with the administrator to limit access to data.
All security boundaries in your data should match those of the storage system. If you store data on a SQL server, this is usually not an issue no matter what the design looks like since you can control access down to the field level. You only have to use these possibilities! Try to collaborate with the system administrator right from the beginning to find a design that not only makes data retrieval easy, but also allows for easy maintenance.
When using DBF files the smallest unit is a file. Hence, a user should either be allowed to access all or no data in a file. If a user is only allowed to see certain fields, you immediately have security issue. In this case, the application has to control access which makes it vulnerable for code injection attacks. If certain fields can only be seen by administrators, put these fields into a second table. Use the primary key to create a one-to-one relationship. Restrict access to the administrator table to the administrator group on the operating system level.
For programs, as well, there are simply techniques to make them more secure. For instance, you could use an include file to replace names in the program with other strings. That's especially easy if you use PRG files for the class definitions. In a .H file you could define, for example:
#DEFINE LineTotal kfjewaoirujsoidfjhoiasdj9424hrfjskjgfhiu943894sfdhkycvnmcxbvxcjh
#DEFINE lnCount kfjewaoirujsoidfjhoiasdj9424hrfjskjdgfhiu943894sfdhkycvnmcxbvxcjh
#DEFINE lnPrice kfjewaoirujsoidfjhoiasdj9424hrfjskjgfhiu943894sfdhkycqvnmcxbvxcjh
#DEFINE lnSum kfjewaoirujsoiidfjhoiasdj9424hrfjskjgfhiu943894sfdhkycvnmcxbvxcjh
If you include this file into all your programs, Visual FoxPro replaces the names when compiling your code. If therefore a user decompiles your application he doesn't see the easy names on the left side, but the slightly more complex ones on the right side. As you probably have quickly noticed, those names have only minor difference which makes them hard to distinguish. This way you make decompilation even easier, especially if some names are contained in other names. Then a hacker can't even easily use search and replace features to replace variables with clear text.
You have to follow some rules, though. There are some things you can't redefine. This includes all property names of VCX based classes, the names of database objects and all names belonging to a table. Since you can only replace generically, you have to exclude such names from the list of #DEFINEs. Pay attention when using macro substitution as the name has been replaced upon compilation and you need to use the long name to access variables. If such a name is used in a string, use  as string delimiter instead of "" or ''. If your application encounters an error, the error message also contains the long name. If your users should be able to report errors on the phone, you need to use simpler names. Best start with _1 and count upwards.
After you prevented external access through encryption and replacing names (obfuscation), or at least raised the bar significantly, you should work on preventing that unauthorized code is executed in your application. The only way to protect against execution of machine code is the integrated user and security management of the operating system. If you give the program and the computer out of your hands, there's nothing you can do. But you have a certain level of control over the execution of VFP code. Especially Visual FoxPro code usually offers the easiest way to access data. Preventing that execution is a huge step forward to securing the application.
First of all, you should include a Config.FPW into your application as this file has precedence over external files. The Config.FPW file is one possibility to execute code before your application run. Especially you can redirect system files to files that are modified and included index expressions, triggers, etc.
If your application happens to notice that the environment is different from what it should look like, immediately quit the application. As this hinders debugging, create special debug versions that do not have this limitation. Never release versions that include debug code. You can be assured that someone finds out how to activate that debug mode. When checking the environment pay attention to the Config.FPW and FoxUser.DBF files, that no tables are open that shouldn't be open, that no settings have been changed, that no FLLs are loaded that shouldn't be loaded and that no ON KEY LABEL are active. In the development environment quit the application immediately, otherwise you risk that the application runs in the debugger. Even if the code is not visible, a hacker can still step through the code line by line and check the contents and the changes of variables and properties.
Verify all inputs before you process them. Remove invalid characters from a string, especially delimiting characters. Check all calls to SQLEXEC(), EXECSCRIPT(), EVALUATE() and the usage of macro substitution.
Before you access a file you should ensure that it hasn't been manipulated. For tables verify the table header and if a table has been added to a database. For index check the expressions. Open a database as a table and validate stored procedures if there are added database events and validation rules have been added to tables. Libraries (FLLs) should be included and copied to disk with a random name before it is loaded. Alternatively use a hash code (MD5) to determine a finger print of the file and validate this hash value every time you load the DLL. This all is quite a lot of work. You rather be sure that you need that level of security.
FoxPro specific files require special attention. VCX, but also SCX, files are easy to extract. Important algorithms therefore belong into a PRG. To extract those from an encrypted application is significantly more difficult.
If you have to use Visual FoxPro reports, check the report file for manipulation like an index. Parse all expressions. Expressions that you can't uniquely identify indicate a potential manipulation. Remove them as they might call external FXP files that perform malicious actions. It's best to include FRX files into the application, too, and copy them out as needed.
To securely use the Visual FoxPro report designer, create a COM EXE server. Instead of accessing encrypted, real data, this EXE accesses a second data directory with test data. These files can be empty or contain sample data. If the user tries to access tables through the report designer, he fails since the COM EXE server has never decrypted the original set of tables. Executing code is limited to the report designer. All saved reports need to be checked for manipulations before they are execute in the real application environment. Remember that you can add reports to a database, too, to execute code before the report is opened. That means, before you open it with USE, you must check the header for manipulations, just like any table.
Even if it's quite tempting to store certain things as VFP programs, be very, very careful with that. Just as easy as you can change these data driven programs, others can make changes not in your interests. Don't assume that such configuration files only contain valid date. If you need to create programs, encrypt them or calculate a checksum using a relatively secure algorithm such as MD5.
If you encrypt files never decrypt them longer than necessary. If, for example, you encrypt the user table, register it only after the user entered a password and deregister it once you have checked the password. Tables for which a user has no rights should not be registered, at all. This might result in each file having a different password, but this method increases security significantly.
Passwords are another critical part. As soon as a password is known, it can be used to compromise your application. Such passwords are often vulnerable to brute force attacks. If a user can take an encrypted file back home, he can use a program to try all possible passwords without being disturbed. Short passwords or passwords that have a meaning as a word are taboo. In the internet there are word lists with hundred of thousands of commonly used passwords (ever wondered how some dubious web sites make their money when there content is free… after you registered with a password?). Such lists are used by hackers, but you, too, should use them to search for your password. Consider that one can check between hundred thousand and several millions Windows passwords per minute if one has certain hash keys from the registry. Especially for passwords used by applications there's absolutely no reason not to use difficult, hard to remember passwords with digits and special characters.
FoxPro tables are inherently insecure as the entire content can be accessed. If you need more security, either use a SQL server, or encapsulate data access into a DCOM/COM EXE server, or use web services to access tables. Then you always have full control about who access which data.
If you have expensive algorithms you should consider not giving the binary code out of your hands. Usually you can't avoid that. If you could offer your application as a web service on your own machine and your client only access the web service, use this possibility. There's no better protection against decompilation.
Consider non-technical aspects, too. If you encounter a violation of the license agreement, you might want to sue the violator. Usually that is only possible in the country of residence of that user. Before you compete with Russian or Chinese lawyers, check with your own lawyer if you can restrict sales and re-sales to countries in which you can use legal actions.
Security is a topic we all should think about more and we will be forced think about more in the future. A lot can be done with zero to nothing efforts if you consider security right from the beginning. Not only web applications are affected, but all kind of applications. Visual FoxPro makes it attackers very easy. A very high degree of security in a Visual FoxPro application is only possible with extremely high efforts and additional tools, if at all.