420 likes | 762 Views
פרויקט באבטחת מידע 236349 - אבטחה חיצונית של בסיס נתונים מצגת סיום. מנחה: עמיחי שולמן מגישות: נדיה גושמיר, יוליה קורצקי. הקדמה.
E N D
פרויקט באבטחת מידע 236349-אבטחה חיצונית של בסיס נתונים מצגת סיום מנחה: עמיחי שולמן מגישות: נדיה גושמיר, יוליה קורצקי
הקדמה • להחלטות אבטחה פנימיות בתוך בסיס נתונים יש חסרונות, חסר מידע חיוני לצורך קבלת ההחלטות הנכונות והבטיחותיות ביותר. נרצה להתערב בתקשורת לקוח - שרת, לקבל החלטות אבטחה חיצוניות לבסיס הנתונים, ולגרום להתנהגות שונה של בסיס הנתונים עפ"י החלטות אלו.
הקדמה(המשך) • אז למה בעצם לכתוב רכיב חיצוני, האם אפשר לאבטח באותה מידה מתוך בבסיס הנתונים? • התשובה היא כן, אבל באופן מאוד לא יעיל. לבסיס הנתונים אין יד משגת לנתונים כגון ip של משתמש או אפילו שעה. ע"מ לאפשר גישה לנתונים מסוג זה יש לממש חבילות הכתובות ב-PL\SQL, דבר זה מסורבל מבחינת מימוש ובסופו של דבר לא יעיל מבחינת ביצועים, דבר שסותר את עיקר בסיס הנתונים, גישה מהירה ונוחה לנתונים שמאוחסנים בו.
הקדמה(המשך) • שימוש נפוץ בבסיסי נתונים הם דרך connection policy, כלומר שרות המספק גישה לבסיס נתונים. ברוב המקרים, הוא מחזיק מספר חיבורים ספורים לבסיס נתונים ומעביר את החיבורים בין הלקוחות. כלומר על חיבור אחד מדברים מס' לקוחות שונים. אבטחה חיצונית של בסיס נתונים במקרה זה יכולה למנוע בעיות בטיחות.
הקדמה(המשך) • אורקל (בסיס הנתונים עימו עבדנו) משתמש בVPD- ו-application context לאכיפת הרשאות גישה. אנו נשתמש בכלים אלו באופן "מניפולטיבי", רכיב האבטחה ישתול בהודעות שעוברות דרכו הודעות piggyback (מקרה נדיר שלא משבש את התקשורת) שיכילו אינפורמציה המעידה על האם יש לאפשר/לחסום גישה ובשלב שההודעה תגיע לשרת אינפורמציה זו תתן אינדקציה לשרת איך לפעול.
הקדמה(המשך) • לסיכום, רכיב האבטחה יקבל החלטות אבטחה ע"ס חוקים ואינפורמציה הקיימת בידו, ובסיס הנתונים יוציאן לפועל.
Proxy • רכיב החוצץ בתקשורת בין הלקוח לשרת. • הלקוח מתנהל מול הרכיב, רכיב מעבד הודעה, ושולח לשרת, השרת מגיב בחזרה לרכיב והודעה זו מועברת ללא שינוי ללקוח. • כל session בין שרת ללקוח מנוהל על ידי שני חוטים, שנוצרים ע"י החוט הראשי האחראי לקבל בקשות התחברות. חוטים אלה הם חד כיוונים, כלומר עבור כל התחברות ישנו חוט האחראי להעביר הודעות מלקוח לשרת, וחוט נוסף האחראי להעביר הודעות משרת ללקוח. • רכיב ה-proxy תומך בהתחברות של מספר לקוחות בו זמנית. כאשר לקוח חדש מתחבר, הרכיב יוצר עבורו שני חוטים חדשים שיהיו אחראים על התקשורת בין לקוח זה לשרת. • הרכיב (החוט הראשי) יושב על פורט 5555 לכן הלקוח שולח הודעות לפורט זה, בעוד השרת עימו עבדנו יושב על פורט 1521.
Application Context • application context מונח המתייחס לקבוצה של זוגות, משתנה וערכו, שמאחסן מסד הנתונים אורקל בזיכרון. • Application context מכיל שם משתנה וערך, שם המשתנה הוא בעצם פוינטר המצביע לערך. אפליקציה יכולה להשתמש ב- Application context ע"מ לקבל מידע עבור session של משתמש מסויים, למשל ה-ID שלו או אינפורמציה כללית נוספת אודות המשתמש, אחסון מידע זה בבסיס הנתונים, מאפשר גישה באופן דינאמי לאינפורמציה רלוונטית ובהתאם להרשות או לאסור גישה למידע דרך האפליקציה. • שימוש נפוץ: כאשר לקוח מתחבר לשרת יש במשתנה SESSION_USER את ה-ID של הלקוח.
Application Context דוגמא: CLIENTCONTEXT– namespace השמת ערך: exec dbms_session.set_context('CLIENTCONTEXT','aaa','bbb'); כעת בבסיס הנתונים יש משתנה בשם aaa שערכו bbb בדיקת ערך: Select sys_context('CLIENTCONTEXT','aaa') from dual; הפלט עבור פקודה זו יהיה bbb
פרוטוקול התקשורת של Oracle • מורכב משני פרוטוקולים שמיוצגים בשתי שכבות. השכבה הראשונה NS (או TNS) מיישמת פרוטוקול פשוט להקמת ערוץ תקשורת בין לקוח מסד נתונים ושרת מסד נתונים. השכבה השנייה TTI מיישמת פרוטוקול מורכב שמעביר סמנטיקת פעולת מסד נתונים בין הצדדים. • הודעות פרוטוקול NS נקראות packets, לאחר הקמת ערוץ התקשורת בין הלקוח לשרת, סוג מיוחד של packetsהנקרא data packetמשמש לעטיפת הודעות TTI. • מאחר ואורקל מיועדת לפעול בסביבה מרובת פלטפורמות, ע"מ לספק תאימות בין גרסאות רבות של שרת ותוכנת הלקוח יש ייצוג מידע מורכב בשכבת ה-TTI. זה מוסיף למורכבות קביעת המיקום של שדות נתונים בתוך ההודעות.
מבנה הודעת Data • בתוך Data נמצאת הודעת TTI, הנפוץ מבין ההודעות ה-TTI הוא מסוג 3 (function calls) השאילות הקונבנציאונליות אשר נשלחות לבסיס נתונים הן מסוג זה, השגת מידע (Fetch) מהבסיס נתונים נעשה ע"י הודעות מסוג זה.
PiggyBack סוג נוסף של הודעות הינו 11, Connection Function Calls ,הודעות "שק קמח" הן הודעות מסוג זה. למשל, הודעות סגירה על statment פתוח נשלחות בהודעת piggyback על ההודעות העתידיות, כלומר בעת סגירה, לא נשלחת ההודעה ישירות לשרת, אלא ממתינים לפעולה הבאה שתצריך גישה לשרת, עליה היא "תרכב" אל השרת. הדבר הזה מתאפשר כי אין חיווי על הודעת סגירה.
PiggyBack - KeyVal ההודעה שאנו שתלנו בהודעות שעברו בתקשרות היא הודעת KEYVAL, הודעה זו היא גם מסוג 11, ומכניסה לבסיס נתונים application contextכרצונינו. הודעות מסוג piggyback הן מקרה נדיר בו ניתן להוסיף אותן להודעות אמיתיות מהלקוח לשרת בלי שיגרמו לתופעות לוואי, הדבר מתאפשר בגלל שאין על הודעות מסוג זה חיווי, לכן מצד אחד שקופות ללקוח, ומצד שני מאפשרות לשנות את ההודעה המקורית של הלקוח לטובתינו ללא כל נזק לפרוטוקול התקשרות
Oracle Virtual Private Database (VPD) • VPD מאפשר ליצור מדיניות אבטחה כדי לשלוט בגישה למסד נתונים. • בעיקרו של דבר, VPD מוסיף תנאי WHERE דינמי לשאילת SQL שמשתמשת בטבלה או מבט שלה הוצמד policy. • מה זה policy? • כאשר משתמש ניגש במישרין או בעקיפין לטבלה, מבט או synonym שמוגן עם Policy , בעזרת VPD, באופן דינמי משתנה שאילתת ה- SQL של המשתמש. שינוי זה נוצר ע"י שירשור WHERE שחוזר על ידי פונקציית ה- policyלשאילתה המקורית. ה-VPD משנה את המשפט באופן דינמי ושקוף למשתמש. ניתן להטיל VPD על הפקודות SELECT, INSERT, UPDATE, INDEX, DELETE .
Oracle Virtual Private Database (VPD) BEGIN DBMS_RLS.ADD_POLICY) object_schema => 'SYSTEM', object_name => 'OE.ORDERS’,// הטבלה שלה מצמידים "משטר" policy_name => 'toDenyAccessCalendar’,// שם המשטר policy_function => 'security’ ;( END; הפונקציה security תופעל כאשר יש גישה לטבלה OE.ORDERS ותחזיר מחרוזת שתוצמד לתנאי WHERE לשאילתה שנשלחה. דוגמא: משתמש מבצע את השאילתא הבאה: SELECT * FROM OE.ORDERS; מנגנון ה-VPDמצרף באופן דינאמי לשאילתה הנ"ל תנאי WHERE והופך אותה ל: SELECT * FROM OE.ORDERS WHERE SALES_REP_ID = 159; כלומר הפונקציה security מחזירה את המחרוזת SALES_REP_ID = 159, כמובן שניתן להחזיר מחרוזות מורכבות יותר, וזה בדיוק מה שנעשה...
יצירת פונקציות ב-PL\SQL יצרנו שתי פונקציות שיקושרו ל-Policyים וישמשו ליישום של החלטות אבטחה בשרת. פונקציות אלה מאוחסנות בשרת מרגע יצירתן. בפונקציות שיצרנו מתבצע שימוש בשני:application context • 'toDenyAccess' – קובע האם לחסום את הגישה או לא. ערך 1 מציין שהתקבלה החלטה לחסום וערך 0 – לא לחסום. • 'numRows' – קובע את מספר השורות שיש להציג בתוצאת השאילתא. הפלט של פונקציות אלו (שהוא ביטוי שבו נבדקים הערכים של 'toDenyAccess' ו- 'numRows') יתווסף כתנאי WHERE (או כתוספת לתנאי WHERE, אם השאילתא המקורית מכילה תנאי זה) לשאילתא אותה שלח הלקוח לשרת.
PL\SQL (המשך) פונקצית security1: CREATE OR REPLACE FUNCTION security1( object_schema IN VARCHAR2, object_name IN VARCHAR2) RETURN VARCHAR2 AS begin return '('|| sys_context('CLIENTCONTEXT','toDenyAccess') ||'= 0)'; end; הפונקציה מחזירה את הביטוי sys_context('CLIENTCONTEXT','toDenyAccess') = 1)) כלומר השוואת הערך המאוחסן ב-'toDenyAccess' לערך 1.
PL\SQL (המשך) פונקצית security2: CREATE OR REPLACE FUNCTION security2 ( object_schema IN VARCHAR2, object_name IN VARCHAR2) RETURN VARCHAR2 AS begin return '('|| sys_context('CLIENTCONTEXT','toDenyAccess') ||'= 1 and ' || 'rownum <=' || sys_context('CLIENTCONTEXT','numRows')||') or ('||sys_context('CLIENTCONTEXT','toDenyAccess') ||'= 0)'; end; כלומר, יש בדיקת הערך המאוחסן ב-'toDenyAccess'. אם הערך 1 (כלומר, יש לבצע חסימה) אז יש להחזיר בפלט השאילתא את מספר השורות המופיע ב-'numRows'. אם ערכו 0 – אז אין לחסום. במקרה זה פלט השאילתא יוצג במלואו ולא תהיה התייחסות לערך ה-‘numRows'.
שיפור ביצועיםשימוש ב-Static Policy כדי למנוע ריצות חוזרות של פונקציות ה-Policy • כדי שהפונקציות המקושרות ל-Policy לא יורצו מחדש בכל הפעלה של ה-Policy, הפכנו את סוג ה-Policy לסטטי, ע"י הוספת התכונה הבאה לכל Policyשמגדיר הרכיב בשרת: policy_type => dbms_rls.STATIC • כעת, הפונקציה רצה פעם אחת ומחזירה מחרוזת פונקציאונלית המכילה קריאה ל-syscontext. בזמן ביצוע ה-Policy, מחושב ערך הביטוי ללא הרצה מחודשת של הפונקציה. • הביטוי המוחזר בריצה היחידה של הפונקציה מאוחסן ב-SGA, והעניין חוסך ריצות חוזרות של הפונקציות ומביא לשיפור בביצועים. • מבדיקה שביצענו: בלי תכונת ה-STATIC– ריצת שאילתא לקחה 2303 יחידות זמן ועם התכונה – 1818.
קובץ החוקים רכיב התוכנה מקבל כקלט קובץ חוקים בפורמטXML . סוגי החוקים הקיימים בכל החוקים הגישה נחסמת לטבלה הספציפית המצוינת בחוק. • max_access - חסימת גישה אחרי מספר מקסימלי של גישות. • ip_access - חסימת גישה עבור IP מסוים. • country_access - חסימת גישה ממדינה מסוימת (עפ"י IP). • colomn_access- חסימת גישה אם ניגשים/לא ניגשים לעמודה מסויימת.
5. calendar_access- חסימת גישה עפ"י ימים: • Day – עפ"י יום בשבוע. • Month - עפ"י חודש מסוים. • Year - עפ"י שנה. • Date - עפ"י תאריך מסוים. 6. time_access - חסימת גישה עפ"י טווח שעות. 7. table_order_access - חסימת גישה אם מתבצעת גישה לטבלאות עפ"י הסדר הנבחר. 8. user_access - חסימת גישה עבור משתמש מסוים. 9. department_access - חסימת גישה עבור משתמשים ממחלקה מסוימת. רשימת המחלקות והמשתמשים של כל מחלקה מאוחסנת ב-database.
מבנה קובץ החוקים תגיות חובה בכל חוק חוק ראשון תגיות המגדירות את הפעולות עבורן יופעל החוק תגיות מיוחדות עפ"י סוגי החוקים קובץ חוקים שלם חוק שני
פענוח החוקים מקובץ ה-XML ע"י רכיב התוכנה הרכיב טוען את החוקים מקובץ ה-XML לרשימה מקושרת של חוקים. החוקים ברשימת זו הם מהטיפוס האבסטרקטי rule. כל אחד מסוגי החוקים (שפורטו קודם) מיוצג ע"י מחלקה היורשת מהמחלקה rule. כל מחלקה כזו (המתאימה לסוג של חוק) מממשת פונקציה המקבלת הודעה, בודקת אותה ומקבלת החלטת אבטחה לגביה – האם יש לחסום את הגישה או לא. למשל חוק מסוגuser_access מיוצג ע"י המחלקה user_access_ruleובה יש פונקציה המקבלת את החלטת האבטחה על סמך תוכן ההודעה הנבדקת ועל סמך הלקוח המחובר כרגע ב-login לשרת. המידע המאוכסן עבור כל סוגי החוקים: שם החוק, כפי שהוא מופיע בקובץ החוקים, שם הטבלה אליה מגבילים את הרשאות הגישה, מספר השורות שיש להציג בפלט השאילתא במקרה של חסימת הגישה, רשימת הפעולות שבהן יש להגביל את הרשאות הגישה. עבור כל סוג של חוק, מאוכסנות תכונות נוספות – הרלוונטיות לכל חוק עפ"י סוגו.
הוספת Policy לטבלאות בשלב פענוח קובץ החוקים מתבצעת התחברות של הרכיב לשרת לשם הוספת Policy לטבלאות המופיעות בחוקים. הוספת ה-policy מתבצעת באופן הבא: עבור כל חוק בקובץ החוקים, אם הופיעו תגיות action עם ערכים שונים מ-SELECT, אז מתבצעת הוספת Policy עם הפונקציה security2. לדוגמא, אם עבור חוק מסויים הופיעו הפעולות UPDATE ו-INSERT הוספת ה-Policy תראה כך: BEGIN DBMS_RLS.ADD_POLICY( object_schema => … object_name => … policy_name=> … policy_function => 'security1', statement_types => 'INSERT,UPDATE'); END; המשמעות של הוספת ה-Policy עם הפונקציה security1 היא שבמידה ותתקבל החלטת אבטחה לחסום את הגישה – הגישה תיחסם לחלוטין.
הוספת Policy לטבלאות (המשך) אם מופיעה תגית action עם הערך SELECT אז מתבצעת הוספת Policy עם הפונקציה security2. כלומר, לדוגמא: BEGIN DBMS_RLS.ADD_POLICY( object_schema => … object_name => … policy_name=> … policy_function => 'security2', statement_types => ‘SELECT'); END; המשמעות של הוספת ה-Policy עם הפונקציה security2 היא שבמידה ותתקבל החלטת אבטחה לחסום את הגישה – הגישה תיחסם כך שיוצגו בפלט השאילתא מספר השורות שנקבעו ע"י החוק.
קבלת החלטות האבטחה כאשר לקוח שולח הודעה לשרת, הודעה זו מגיעה לרכיב. ברכיב, ההודעה מפוענחת ונבדקת ואז מתקבלת החלטת אבטחה לגביה. בדיקת תוכן ההודעה מבצעת ע"י מעבר בלולאה על כל החוקים שנמצאים ברשימת החוקים ובדיקה האם קיים חוק התואם את תוכן ההודעה הנבדקת. במידה ואף חוק לא תואם, החלטת האבטחה תהיה לא לחסום את הגישה. אחרת בוחרים את החוק המגביל בצורה ה"חמורה" ביותר את הגישה, והחלטת האבטחה תהיה לחסום את הגישה באופן זה.
העברת החלטות האבטחה מהרכיב לשרת במידה וההחלטה שהתקבלה היא לא לחסום את הגישה, מעבירים לשרת את ההודעה מהלקוח ללא שינוי. במידה והתקבלה החלטה להגביל את הרשאות הגישה, שותלים בהודעה שתי הודעות מסוג KEYVAL. כל KEYVAL כזה מבצע השמה של ערך ל-application context הרצוי. הראשון מבצע השמה ל- toDenyAccess (הקובע האם יש לחסום את הגישה) והשני מבצע השמה ל- numRows (המחזיק את מספר הרשומות שמותר להראות, במידה והוחלט לחסום את הגישה).
ביצוע החלטות האבטחה (שהתקבלו מהרכיב)ע"י השרת ברגע שהשרת מקבל מהלקוח הודעה עם ניסיון לבצע שאילתא על טבלה מסויימת, מופעלים אוטומטית ה-Policyים המתייסחים לטבלה זו. בזמן הפעלת ה-Policy , מחושב ערך הביטוי שהוחזר מהפונקציה המקושרת ל-Policy זה (security1 או security2 – בהתאם למה שנשתל ב-Policy). בשלב הזה מתבצעת בדיקה של ערכי משתני ה- application context שהועברו לשרת, כלומר נבדקים ערכי ה-toDenyAccess וה-numRows. ביטוי זה נשתל בתור תנאי WHERE לשאילתא הנתונה. בדרך זו, החלטות האבטחה מבוצעות ע"י השרת.
שתילת PiggyBack בהודעות רכיב ה- proxy, מקבל הודעה מהלקוח, מפענח אותה, ובמידה וההודעה תואמת לחוק, מוסיף לה piggyback מסוג KEYVAL, אשר שם במשתנה (application context) בבסיס הנתונים ערך מתאים. איך זה נעשה? נסתכל על חוק לדוגמא: <rule type="time_access"> <rule_name>rule12</rule_name> <table_name>RULES_TABLE11</table_name> <action>SELECT</action> <num_rows>1</num_rows> <startTime>18:00</startTime> <endTime>21:00</endTime> </rule>
כלומר בטווח השעות 18:00-21:00 אסור לגשת לטבלה .RULES_TABLE11 נניח שבשעה 20:00 נשלחת ההודעה .select * from RULES_TABLE11 מאחר וחוק זה מכיל num_rows שערכו 1, פלט השאילתה יחזיר רשומה אחת לכל היותר. לצורך מימוש החוק, נשתול שתי הודעות piggyback להודעה המקורית. *ההודעות מוצגות ב-hexadecimal ההודעה המקורית: 00 68(size) 00 00 06 00 00 00 00 00 11 69 00 01 01 01 01 02 03 5e(fetch) 00 02 80 21 00 01 01 1b 01 01 0d 00 00 04 ffffffff 01 32 04 7f ffffff 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 53 45 4c 45 43 54 20 2a 20 46 52 4f 4d 20 52 55 4c 45 53 5f 54 41 42 4c 45 31 31 01 01 00 00 00 00 00 00 01 01 00 00 00 00 00
ההודעה לאחר הוספת ה-Piggyback: 00 bf 00 00 06 00 00 00 00 00 11 9a 00 01 01 0d 01 01 01 01 01 01 43 4c 49 45 4e 54 43 4f 4e 54 45 58 54 01 07 07 6e 75 6d 52 6f 77 73 01 01 01 31 01 01 11 9a 00 01 01 0d 01 01 01 01 01 01 43 4c 49 45 4e 54 43 4f 4e 54 45 58 54 01 0c 0c 74 6f 44 65 6e 79 41 63 63 65 73 73 01 01 01 31 01 01 11 69 00 01 01 01 01 02 03 5e 00 02 80 21 00 01 01 1b 01 01 0d 00 00 04 ffffffff 01 32 04 7f ffffff 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 53 45 4c 45 43 54 20 2a 20 46 52 4f 4d 20 52 55 4c 45 53 5f 54 41 42 4c 45 31 31(RULES_TABLE11) 01 01 00 00 00 00 00 00 01 01 00 00 00 00 00 ניתן לראות כי גודל ההודעה המקורית הוא 680x כלומר 104 בתים. הוספנו שתי הודעות piggyback שגודלן ביחד 87 בתים, ואכן הגודל החדש של ההודעה הינו 0xbf שזה 191 בתים.
11 9a 00 01 01 0d 01 01 01 01 01 01 43 4c 49 45 4e 54 43 4f 4e 54 45 58 54 01 07 07 6e 75 6d 52 6f 77 73 01 01 01 31 01 01 11 9a 00 01 01 0d 01 01 01 01 01 01 43 4c 49 45 4e 54 43 4f 4e 54 45 58 54 01 0c 0c 74 6f 44 65 6e 79 41 63 63 65 73 73 01 01 01 31 01 01 6e 75 6d 52 6f 77 73 (variable name = numRows) 01 - length of Value length 01 - Value length 01 - Value length for the string 31 = "1" // one row is allowd to be seen 01 – flag Another piggyBack: 01 11 9a 00 01 01 0d 01 01 01 01 01 01 43 4c 49 45 4e 54 43 4f 4e 54 45 58 54 01 0c 0c(12) 74 6f 44 65 6e 79 41 63 63 65 73 73(variable name= "toDenyAccess") 01 01 01 31 01 01 11 9a- KEYVAL 00 - sequence number 01 - ptr 01 - length of namespace length 0d - length of namespace ("CLIENTCONTEXT".len()=13=0x0d) 01 - ptr 01 - length of Number of values 01 - Number of values 01 - length of Flags 01 - Flags 01- PTR 43 C 4c L 49 I 45 E 4e N 54 T 43 C 4f O 4e N 54 T 45 E 58 X 54 T 01 - length of Name length 07 - Name length 07- Name length for the string
כעת בבסיס הנתונים יש שני משתנים toDenyAccess ו-numRows עם ערכים עדכניים. כפי שרואים בהודעה המלאה, ה-Piggyback נשתל בתחילת ההודעה המקורית. לכן, המשתנים מתעדכנים לפני ביצוע השאילתא. במידה והושם במשתנה החסימה הערך 1, בהודעה הבאה - במידה ואף חוק לא תאם, יושם בו הערך 0, על מנת לא לחסום (זהו משתנה סטטי ששומר את הערך האחרון שהושם בבסיס הנתונים).
כלים Oracle Server – שרת מסד הנתונים. נמצא במכונה וירטואלית. SQL Developer – הלקוח של מסד הנתונים. הגישה למסד הנתונים מתבצעת דרכו. XML – קובץ החוקים, אותו רכיב התוכנה מקבל בתור קלט. Java Eclipse – סביבת העבודה בה נכתב רכיב התוכנה. נעשה שימוש ב -jar sqljdbc4 ,ojdbc6.
מקורות • Oracle network protocol documentation (Amichai Shulman) • Oracle Database Concepts 11g Release 2 (11.2): chapter 8: 8 Server-Side Programming: PL/SQL andJava (excluding Java( chapter 4: 4 Partitions, Views and other Schema objects 1. Overview of Views 2. Overview of Synonyms • Oracle Database Security Guide 11g Release 2 (11.2): chapter 6: Using Application Contexts to Retrieve User Information chapter 7: Using Oracle Virtual Private Database to Control Data Access chapter 8: Developing Applications Using the Data Encryption API