Access Trap
Security Model for Web Suites
This artical covers Access_Trap, which is the security environment used in Picture Placemat (web based photo management suite)
Description
Access_Trap provides a secure environment using a Referer test for Authorization between scripts and a user/password test for Authentication.
Although Access Trap was created for Picture Placemat it could be adapted for use in any number of applications.
This article discusses the role of Access Trap as it relates to Picture Placemat.
Security Highlights
- all the Admin related scripts are under it's control
- the admin tool scripts can only be accessed via the ppm_admin.sh script, which is the login screen
- the ppm_admin.sh page can only be accessed via a "Admin Login" button on the PPM Main page
- access to any of the protected pages can only come via an authorized link, not a typed in url (not even after auth in the admin page)
- a manual refresh of the page kicks you out and sends you to the PPM Main page
- there are no passwords stored in clear text (user & password stored in file are already encrypted), and the encryption is one-way
- for compatibility it uses GET in web forms but user/pass in the url are immediately removed before the page is displayed, so no sensitive information is visible in the browsers url field
- the encrypted password process cannot be used for DB creds in the lib file because they need to be sent to mysql in the clear, and this uses one-way encryption
- all scripts have permissions of 500, except one user populated library file which is 700 (may auto that to go 700 during updates only)
- the Admin Tools have their own library file for functions and variables, which is also protected under the security scheme
- there are variables to set min and max length of both username and password
Details
- Authorization:
- Since HTTP Referer header is only sent thru a activated link on a page it prevents the user from directly accessing the tools area.
When you type a url in you are not coming from another page so there is no referer.
By checking the referer we know for sure where the request came from, and it must come from one of the admin pages, or it may come from the home page but then it can only access the login screen.
Any other attempts to load any of the protected pages in any other way will result in a redirection back to the home page.
- All protected scripts have a first step call to the auth_check function to see they were called from.
- The admin pages are identified by a list in the protected list which contains the main login screen name and a pattern used for all other tools.
So if you add a new tool script with the call to auth_check in it, and it uses the expected name pattern it is automatically protected.
- In order to expose a script you would need to have enough access to rename it, modify it to remove the check_auth call, or be able to modify/over-write the admin function library.
- Authentication:
- There is a login form to enter Admin Name & Admin Password. It's passed to a script which encrypts the user supplied creds and compares them to the encrypted username and password stored in a separate file.
- If the creds match then they are redirected to a main admin tools page where all admin tools can be accessed.
- If there is no match (auth failure), the login page reloads with no additional messages.
- First Run:
- The first time that happens when you load the main page is it checks for the user populated library file (there are several lib files but that one does not initially exist).
- If the expected file is there it loads the main page, but if it does not exist it loads a initial setup script. The script will run some system checks and ask the user for some additional information needed to get things working.
- Once done and the user clicks to continue, it loads the admin login script.
- The login script immediately checks for and deletes the initial setup script.
- If the users referer is the setup script and if the setup script existed and if the admin script could delete it, then a new user/password page is presented.
- After creating an accepted name and confirming an accepted password, the creds are encrypted and written to a file, which is then set to 500.
This is a new file on first run but if changing creds later it is set to 700, over written, then set back to 500.
- If the user enters an invalid length field or the password does not match the 'verify password', then the page reloads saying one of the items is wrong, nothing else.
Layout
ppm_home.sh
│ └── links to viewing scripts and common libraries
│
Aceess Controlled via auth_check and auth_user_check functions
│
└── ppm_admin.sh (login) ────────────────────────
│ │ │
│ └── ppm-admin_auth.sh (encrypted creds) │
│ ├── ppm-admin_libs.sh
└─ ppm-admin_main.sh (Admin tool links) ─────│ (shared admin libraries)
│ │
└── various admin scripts for tools ──────
The Code
This is the entire access control code which is called at the start of all admin scripts.
It is a function that see's where the request came from (HTTP_REFERER, with page name in it) and what the request string was (REQUEST_URI).
Then it does a bunch of if-elif-else stuff and decides what to do with you.
Authorization:
###############################################
# Authorization for Admin Pages #
# the main admin page also has an authentication check (auth_user_check).
auth_check() {
START_PAGE="/cgi-bin/ppm_home.sh" # this is the page you have the "go to admin" button/link on
GOTO_PAGE="/cgi-bin/ppm_home.sh" # this is where you send requests that are disallowed access
SETUP_PAGE="/cgi-bin/ppm_setup-env.sh" # this is a temp page used for initial setup
ADMIN_LOGIN_FILE="ppm_admin.sh"
ADMIN_LOGIN_PAGE="/cgi-bin/${ADMIN_LOGIN_FILE}"
ADMIN_PAGES="ppm-admin_*.sh"
# set auth to false
AUTH_OK=0
ALLOW_LOGIN_ATTEMP=0
#ADMIN_PAGES="ppm_admin.sh `ls ppm-admin*.sh`"
ADMIN_PAGES="${ADMIN_LOGIN_FILE} `ls ${ADMIN_PAGES}`"
#ADMIN_PAGES="` ls ${ADMIN_PAGES}`"
# are they returning from a tool (already authed)
# eg. HTTP_REFERER=http://nesbitt.linux1.ca/cgi-bin/ppm-admin_sometool.sh
for script_name in ${ADMIN_PAGES}
do
SCRIPT_REFERER="http://${DOMAIN}/cgi-bin/${script_name}"
THIS_REFERER=`echo ${HTTP_REFERER} | cut -d\? -f1`
if [ "${THIS_REFERER}" = "${SCRIPT_REFERER}" ];then
AUTH_OK=1
fi
done
# must allow access to admin page from home or from set-up page (triggered first run), but should still prompt
echo "${REQUEST_URI}" | grep "${ADMIN_LOGIN_PAGE}" &> /dev/null
URI_VAL=$?
if ( [ "${THIS_REFERER}" = "http://${DOMAIN}${START_PAGE}" ] && [ ${URI_VAL} -eq 0 ] ) || ( [ "${THIS_REFERER}" = "http://${DOMAIN}${SETUP_PAGE}" ] && [ ${URI_VAL} -eq 0 ] );then
ALLOW_LOGIN_ATTEMP=1
fi
# case where login (ADMIN_LOGIN_FILE) reloads to check submitted creds, must not set AUTH_OK=1
echo "${REQUEST_URI}" | grep "${ADMIN_LOGIN_PAGE}" &> /dev/null
ADMIN_REFER_VAL=$?
echo "${THIS_REFERER}" |grep "http://${DOMAIN}${ADMIN_LOGIN_PAGE}" &> /dev/null
REFER_MATCHES=$?
LOGIN_CHECK=0
#if [ "${THIS_REFERER}" = "http://${DOMAIN}${ADMIN_LOGIN_PAGE}" ] && [ ${ADMIN_REFER_VAL} -eq 0 ];then
if [ ${REFER_MATCHES} -eq 0 ] && [ ${ADMIN_REFER_VAL} -eq 0 ];then
AUTH_OK=0
LOGIN_CHECK=1
fi
#############
# act_on_auth
if [ ${AUTH_OK} -ne 1 ] && [ ${LOGIN_CHECK} -ne 1 ]; then
if [ ${ALLOW_LOGIN_ATTEMP} -ne 1 ];then
# send them away
cat << EOAF
Status: 303
Location: /cgi-bin/ppm_home.sh
EOAF
exit
fi
fi
}
##### e/o admin auth check ######
Authentication:
Authentication is controlled by the script that presents the Admin Login (ppm_admin.sh).
It is just 2 small functions.
The first encrypts and compare the provided creds
On a successful match, the second function is called to send the user to the main admin tools area.
Below, the vars ADMIN_NAME & ADMIN_PASSWD are received from user input, and REAL_IMG_ADMIN & REAL_IMG_PASSWD are encrypted variables defined in an separate admin auth file.
## compare provided creds
auth_user_check() {
AUTH_USER=0 # set auth to false
ADMIN_NAME_CRYPT=`perl -le "print crypt(\"${ADMIN_NAME}\", 13)"`
ADMIN_PASSWD_CRYPT=`perl -le "print crypt(\"${ADMIN_PASSWD}\", 13)"`
if [ "${ADMIN_NAME_CRYPT}" = "${REAL_IMG_ADMIN}" ] && [ "${ADMIN_PASSWD_CRYPT}" = "${REAL_IMG_PASSWD}" ]; then
AUTH_USER=1
fi
if [ ${AUTH_OK} -eq 1 ];then # AUTH_OK comes from auth_check
AUTH_USER=1
fi
}
## act on auth results
act_on_auth_ok() {
if [ ${AUTH_USER} -eq 1 ];then # login was okay, send them to main page
cat << EOH
Status: 303
Location: /cgi-bin/ppm-admin_main.sh
EOH
exit
fi
}
Known Weaknesses
- forged http-headers could bypass the login process and directly access the protected pages
- if the cgi-bin directory is compromised
- if the filenames are changed so they do not match the expected pattern, then they will not be included in the checks
- if the call to 'auth_check' is removed from the protected file
- there is also a browser back-button issue since there is no logout
original document created by Pete Nesbitt, May 2011