How to protect Python source from modification
frank at chagford.com
Tue Sep 13 10:00:37 CEST 2005
Dennis Lee Bieber wrote:
> On 12 Sep 2005 08:33:10 -0700, "Frank Millman" <frank at chagford.com>
> declaimed the following in comp.lang.python:
> > My problem is that, if someone has access to the network and to a
> > Python interpreter, they can get hold of a copy of my program and use
> > it to knock up their own client program that makes a connection to the
> > database. They can then execute any arbitrary SQL command.
> If your DBMS is directly accessible on the net, you're vulnerable
> even without Python. Especially if you have "authentication" logic being
> done at the client end. There is nothing to prevent someone using a
> compatible query browser or command-line utility to make connection
> attempts to the server, followed by classical username/password cracking
Right - this is the conclusion I have come to.
> > The server program is currently programmed to accept a number of
> > message types from the client program. Each message's data string
> > starts with a numeric prefix, which indicates the type of message,
> > followed by a pickled tuple of arguments. The server program reads the
> > string, extracts the numeric prefix, and passes the rest of the string
> > to the appropriate function using a subthread.
> Ah, okay -- you /do/ already have something running in the middle.
It is more on the side than in the middle at present - the client
connects to my server program, but also connects directly to the
database. My proposed change is to put it really in the middle - the
client connects to my server, and my server connects to the database.
> > For example, I keep track of who is currently logged in. On startup,
> > the client connects to my server and sends a '1' followed by their
> > userid and other information. The server receives this and passed the
> > data to a 'login' function, which uses a Python dictionary to store the
> > information. If the server detects that the user is already logged in,
> > it sends back an error code and the client program displays a message
> > and terminates. Otherwise it sends back an 'ok' code, and the client
> > can continue. When the client logs off, it sends a '2' followed by
> > their userid, which the server receives and passes it to a 'logoff'
> > function, which deletes the entry from the dictionary.
> Obscuring the Python stuff will only be a minor delay factor in
> breaking that -- someone really serious could probably stick in a packet
> sniffer and record a transaction sequence, eventually reverse mapping
> back to the types of operations each code represents.
Would using SSL be a solution? This is on my to do list.
> Database security? First step would be to USE the DBMS privilege
> system to limit operations to only those SQL statements, tables, and
> data columns that are needed for your client program; since you appear
> to be using user/password information already, each such user could have
> different privileges, limiting some to retrieval only, for example. As
> for your "server", I'd probably start a thread for each connected user,
> so that thread handles all communication. Your description sounds more
> like a rudimentary proxy adding in a counting scheme, but not really
> isolating separate client connections.
A number of replies have indicated that I should be using the DBMS
itself to manage security. I think there are some benefits to managing
it via the application. Admittedly I did not think it through when I
started, but now that I have a reasonable security model working, I
would not want to give it up. Here are some examples of what I can do.
1. Users and groups can be maintained by anyone using my app (with the
correct permissions, of course). You do not have to go through the
database adminstrator with all the complication or red tape that could
2. I am a great believer in 'field-by-field' validation when doing data
entry, instead of filling in the entire form, submitting it, and then
being informed of all the errors. I can inform a user straight away if
they try to do something they are not entitled to.
3. I can cater for the situation where a user may not have permission
to do something, but they can call a supervisor who can override this.
I have seen solutions which involve prompting for a password, but this
has to be programmed in at every place where it might be required. I
allow the supervisor to enter their userid and password, and my program
reads in their permissions, which become the active ones until
cancelled. I create a flashing red border around the window to warn
them not to forget.
There is some support for this approach given by MS SQL Server, which
has the concept of an Application Role. 'Application roles contain no
users, though you can still assign permissions to application roles.
They are designed to let an application take over the job of
authenticating users from SQL Server.'
Thanks for the interesting comments.
More information about the Python-list