Make saving the proxy data secure, and add some notes to the security document

This commit is contained in:
Richard Hughes 2009-07-17 11:09:37 +01:00
parent e59ba218c6
commit 2f742a809a
4 changed files with 62 additions and 40 deletions

View File

@ -91,3 +91,22 @@ Possible attack vectors:
(MaximumPackagesToProcess) for each method, and also limiting the total length
of the data.
* The HTTP and FTP proxies that are sent by the session may contain embedded
usernames and passwords. Whilst these are sent in plain text over the system
D-Bus (FIXME?), the database is not be readable by users (mode 0640).
* The matching of UID and session to proxies assumes that the user cannot
modify the login UID, and cannot spoof a session in ConsoleKit. If a user were
able to change the apparent UID, then this would allow them to use proxy
settings set from another user.
This is manifested when a graphical application is run using sudo (which you
should never do, but I digress) and different proxy settings may be used from
the user settings. It also allows applications run using sudo to use the proxy
specified by root, which may be different.
* We save the UID and session to a database to get the proxy state for each
transaction. If the user is able to create a large number of different sessions
then this will add many entries to the database. Some rate-limiting could be
added to ConsoleKit or PackageKit to solve this, but has not been done at this
time.

View File

@ -27,29 +27,3 @@ proxy settings and this is passed to the backend. This also allows the daemon to
have to correct proxy settings if the daemon times out (as it is designed to do)
and is restarted by a client application using DBus system activation.
Implementation considerations;
The PID and session should be be cached in PkDbus as these will be used on each transaction.
Security considerations:
The HTTP and FTP proxies that are sent by the session may contain embedded
usernames and passwords. Whilst these are sent in plain text over the system
DBus (TODO), the database should not be readable by a user as this could be used
to discover proxy server passwords.
The matching of UID and session to proxies assumes that the user cannot modify
the login UID, and cannot spoof a session in ConsoleKit. If a user were able to
change the apparent UID, then this would allow them to use proxy settings set
from another user. This is manifested when a graphical application is run using
sudo (which you should never do, but I digress) and different proxy settings may
be used from the user settings. It also allows applications run using sudo to
use the proxy specified by root, which may be different.
We save the UID and session to a database to get the proxy state for each
transaction. If the user is able to create a large number of different sessions
then this will add many entries to the database. Some rate-limiting could be
added to ConsoleKit or PackageKit to solve this, but has not been done at this
time.
TODO: need to check for injected SQL in the proxy data before we add freeform text.

View File

@ -95,7 +95,7 @@ pk_dbus_get_pid (PkDbus *dbus, const gchar *sender)
g_return_val_if_fail (dbus->priv->proxy_pid != NULL, G_MAXUINT);
g_return_val_if_fail (sender != NULL, G_MAXUINT);
/* get pid from DBus (quite slow) */
/* get pid from DBus (quite slow) - TODO: cache this */
ret = dbus_g_proxy_call (dbus->priv->proxy_pid,
"GetConnectionUnixProcessID", &error,
G_TYPE_STRING, sender,

View File

@ -683,13 +683,12 @@ gboolean
pk_transaction_db_set_proxy (PkTransactionDb *tdb, guint uid, const gchar *session,
const gchar *proxy_http, const gchar *proxy_ftp)
{
gchar *error_msg = NULL;
gchar *statement = NULL;
gchar *timespec = NULL;
gchar *proxy_http_tmp = NULL;
gchar *proxy_ftp_tmp = NULL;
gboolean ret = FALSE;
gint rc;
sqlite3_stmt *statement = NULL;
g_return_val_if_fail (PK_IS_TRANSACTION_DB (tdb), FALSE);
g_return_val_if_fail (uid != G_MAXUINT, FALSE);
@ -703,13 +702,27 @@ pk_transaction_db_set_proxy (PkTransactionDb *tdb, guint uid, const gchar *sessi
/* any data */
if (proxy_http_tmp != NULL || proxy_ftp_tmp != NULL) {
statement = g_strdup_printf ("UPDATE proxy SET proxy_http = '%s', proxy_ftp = '%s' WHERE uid = '%i' AND session = '%s'",
proxy_http, proxy_ftp, uid, session);
egg_debug ("updated proxy for uid:%i and session:%s", uid, session);
rc = sqlite3_exec (tdb->priv->db, statement, NULL, NULL, &error_msg);
/* prepare statement */
rc = sqlite3_prepare_v2 (tdb->priv->db,
"UPDATE proxy SET proxy_http = ?, proxy_ftp = ? WHERE uid = ? AND session = ?",
-1, &statement, NULL);
if (rc != SQLITE_OK) {
egg_warning ("SQL error: %s", error_msg);
sqlite3_free (error_msg);
egg_warning ("failed to prepare statement: %s", sqlite3_errmsg (tdb->priv->db));
goto out;
}
/* bind data, so that the freeform proxy text cannot be used to inject SQL */
sqlite3_bind_text (statement, 1, proxy_http, -1, SQLITE_STATIC);
sqlite3_bind_text (statement, 2, proxy_ftp, -1, SQLITE_STATIC);
sqlite3_bind_int (statement, 3, uid);
sqlite3_bind_text (statement, 4, session, -1, SQLITE_STATIC);
/* execute statement */
rc = sqlite3_step (statement);
if (rc != SQLITE_DONE) {
egg_warning ("failed to execute statement: %s", sqlite3_errmsg (tdb->priv->db));
goto out;
}
goto out;
@ -717,20 +730,36 @@ pk_transaction_db_set_proxy (PkTransactionDb *tdb, guint uid, const gchar *sessi
/* insert new entry */
timespec = pk_iso8601_present ();
statement = g_strdup_printf ("INSERT INTO proxy (created, uid, session, proxy_http, proxy_ftp) VALUES ('%s', '%i', '%s', '%s', '%s')",
timespec, uid, session, proxy_http, proxy_ftp);
egg_debug ("set proxy for uid:%i and session:%s", uid, session);
rc = sqlite3_exec (tdb->priv->db, statement, NULL, NULL, &error_msg);
/* prepare statement */
rc = sqlite3_prepare_v2 (tdb->priv->db,
"INSERT INTO proxy (created, uid, session, proxy_http, proxy_ftp) VALUES (?, ?, ?, ?, ?)",
-1, &statement, NULL);
if (rc != SQLITE_OK) {
egg_warning ("SQL error: %s", error_msg);
sqlite3_free (error_msg);
egg_warning ("failed to prepare statement: %s", sqlite3_errmsg (tdb->priv->db));
goto out;
}
/* bind data, so that the freeform proxy text cannot be used to inject SQL */
sqlite3_bind_text (statement, 1, timespec, -1, SQLITE_STATIC);
sqlite3_bind_int (statement, 2, uid);
sqlite3_bind_text (statement, 3, session, -1, SQLITE_STATIC);
sqlite3_bind_text (statement, 4, proxy_http, -1, SQLITE_STATIC);
sqlite3_bind_text (statement, 5, proxy_ftp, -1, SQLITE_STATIC);
/* execute statement */
rc = sqlite3_step (statement);
if (rc != SQLITE_DONE) {
egg_warning ("failed to execute statement: %s", sqlite3_errmsg (tdb->priv->db));
goto out;
}
ret = TRUE;
out:
if (statement != NULL)
sqlite3_finalize (statement);
g_free (timespec);
g_free (statement);
g_free (proxy_http_tmp);
g_free (proxy_ftp_tmp);
return ret;