CodeGym /בלוג Java /Random-HE /אבטחה ב-Java: שיטות עבודה מומלצות
John Squirrels
רָמָה
San Francisco

אבטחה ב-Java: שיטות עבודה מומלצות

פורסם בקבוצה
אחד המדדים החשובים ביותר ביישומי שרת הוא אבטחה. זהו סוג של דרישה לא פונקציונלית . אבטחה ב-Java: שיטות עבודה מומלצות - 1אבטחה כוללת מרכיבים רבים. כמובן, יידרש יותר ממאמר אחד כדי לכסות באופן מלא את כל עקרונות האבטחה ואמצעי האבטחה הידועים, אז נתעכב על החשוב ביותר. אדם הבקיא בנושא זה יכול להגדיר את כל התהליכים הרלוונטיים, להימנע מיצירת חורי אבטחה חדשים, ויהיה צורך בכל צוות. כמובן, אתה לא צריך לחשוב שהאפליקציה שלך תהיה מאובטחת ב-100% אם תפעל לפי הנהלים האלה. לא! אבל זה בהחלט יהיה בטוח יותר איתם. בוא נלך.

1. לספק אבטחה ברמת שפת Java

קודם כל, אבטחה בג'אווה מתחילה ממש ברמת היכולות של השפה. מה היינו עושים אם לא היו משנים גישה? לא תהיה דבר מלבד אנרכיה. שפת התכנות עוזרת לנו לכתוב קוד מאובטח וגם עושה שימוש בתכונות אבטחה מרומזות רבות:
  1. הקלדה חזקה. Java היא שפה בהקלדה סטטית. זה מאפשר לתפוס שגיאות הקשורות לסוג בזמן ריצה.
  2. משנה גישה. אלה מאפשרים לנו להתאים אישית גישה למחלקות, שיטות ושדות לפי הצורך.
  3. ניהול זיכרון אוטומטי. בשביל זה, למפתחי Java יש אספן אשפה שמשחרר אותנו מהצורך להגדיר הכל באופן ידני. כן, לפעמים מתעוררות בעיות.
  4. אימות קוד בייט : Java מורכבת לקוד בייט, שנבדק על ידי זמן הריצה לפני ביצועו.
בנוסף, ישנן המלצות אבטחה של אורקל . כמובן, הוא לא כתוב בשפה נעלה ואתם עלולים להירדם כמה פעמים בזמן הקריאה, אבל זה שווה את זה. במיוחד, המסמך שכותרתו Secure Coding Guidelines for Java SE חשוב. הוא מספק עצות כיצד לכתוב קוד מאובטח. מסמך זה מעביר כמות עצומה של מידע שימושי ביותר. אם יש לך הזדמנות, אתה בהחלט צריך לקרוא אותו. כדי לעורר את העניין שלך בחומר זה, הנה כמה טיפים מעניינים:
  1. הימנע מסידרה של שיעורים רגישים לאבטחה. סריאליזציה חושפת את ממשק המחלקה בקובץ המסודר, שלא לדבר על הנתונים שמועברים בסידרה.
  2. נסה להימנע משיעורים שניתנים לשינוי עבור נתונים. זה מספק את כל היתרונות של מחלקות בלתי ניתנות לשינוי (למשל בטיחות חוטים). אם יש לך אובייקט שניתן לשינוי, זה יכול להוביל להתנהגות בלתי צפויה.
  3. צור עותקים של אובייקטים הניתנים לשינוי שהוחזרו. אם שיטה מחזירה הפניה לאובייקט פנימי שניתן לשינוי, אז קוד הלקוח יכול לשנות את המצב הפנימי של האובייקט.
  4. וכולי…
בעיקרון, הנחיות קידוד מאובטח עבור Java SE הוא אוסף של טיפים וטריקים כיצד לכתוב קוד Java בצורה נכונה ומאובטחת.

2. הסר את פגיעויות הזרקת SQL

זהו סוג מיוחד של פגיעות. זה מיוחד מכיוון שהוא גם אחת הפגיעות המפורסמות וגם אחת הפגיעות הנפוצות ביותר. אם מעולם לא התעניינתם באבטחת מחשבים, אז לא תדעו על כך. מהי הזרקת SQL? זוהי מתקפת מסד נתונים הכוללת הזרקת קוד SQL נוסף במקום בו הוא אינו צפוי. נניח שיש לנו שיטה שמקבלת איזשהו פרמטר לשאילתה במסד הנתונים. לדוגמה, שם משתמש. קוד פגיע ייראה בערך כך:
// This method retrieves from the database all users with a certain name
public List findByFirstName(String firstName) throws SQLException {
   // Connect to the database
   Connection connection = DriverManager.getConnection(DB_URL, USER, PASS);

   // Compose a SQL database query with our firstName
   String query = "SELECT * FROM USERS WHERE firstName = " + firstName;

   // Execute the query
   Statement statement = connection.createStatement();
   ResultSet result = statement.executeQuery(query);

   // Use mapToUsers to convert the ResultSet into a collection of users.
   return mapToUsers(result);
}

private List mapToUsers(ResultSet resultSet) {
   // Converts to a collection of users
}
בדוגמה זו, שאילתת SQL מוכנה מראש בשורה נפרדת. אז מה הבעיה, נכון? אולי הבעיה היא שעדיף להשתמש ב-String.format ? לא? נו, מה אז? הבה נכניס את עצמנו לנעליו של בוחן ונחשוב מה ניתן להעביר כערך של firstName . לדוגמה:
  1. אנחנו יכולים להעביר את מה שמצופה - שם משתמש. אז מסד הנתונים יחזיר את כל המשתמשים עם השם הזה.
  2. אנחנו יכולים להעביר מחרוזת ריקה. אז כל המשתמשים יוחזרו.
  3. אבל אנחנו יכולים גם להעביר את הדברים הבאים: "'; DROP TABLE USERS;". והנה יש לנו עכשיו בעיות יואוו. שאילתה זו תמחק טבלה ממסד הנתונים. יחד עם כל הנתונים. כל זה.
האם אתה יכול לדמיין את הבעיות שזה יגרום? מעבר לזה, אתה יכול לכתוב מה שאתה רוצה. ניתן לשנות את שמות כל המשתמשים. אתה יכול למחוק את הכתובות שלהם. היקף החבלה הוא עצום. כדי להימנע מכך, עליך למנוע הזרקה של שאילתה מוכנה ובמקום זאת ליצור את השאילתה באמצעות פרמטרים. זו צריכה להיות הדרך היחידה ליצור שאילתות מסד נתונים. כך תוכל לבטל את הפגיעות הזו. לדוגמה:
// This method retrieves from the database all users with a certain name
public List findByFirstName(String firstName) throws SQLException {
   // Connect to the database
   Connection connection = DriverManager.getConnection(DB_URL, USER, PASS);

   // Create a parameterized query.
   String query = "SELECT * FROM USERS WHERE firstName = ?";

   // Create a prepared statement with the parameterized query
   PreparedStatement statement = connection.prepareStatement(query);

   // Pass the parameter's value
   statement.setString(1, firstName);

   // Execute the query
   ResultSet result = statement.executeQuery(query);

   // Use mapToUsers to convert the ResultSet into a collection of users.
   return mapToUsers(result);
}

private List mapToUsers(ResultSet resultSet) {
   // Converts to a collection of users
}
כך נמנעת הפגיעות. למי שרוצה לצלול עמוק יותר לתוך מאמר זה, הנה דוגמה מצוינת . איך אתה יודע מתי אתה מבין את הפגיעות הזו? אם הבנתם את הבדיחה בקומיקס למטה, כנראה שיש לכם הבנה ברורה במה מדובר בפגיעות זו :Dאבטחה ב-Java: שיטות עבודה מומלצות - 2

3. סרוק תלות ושמור אותן מעודכנות

מה זה אומר? אם אתה לא יודע מהי תלות, אני אסביר. תלות היא ארכיון JAR עם קוד שמחובר לפרויקט באמצעות מערכות בנייה אוטומטיות (Maven, Gradle, Ant) על מנת לעשות שימוש חוזר בפתרון של מישהו אחר. לדוגמא, Project Lombok , שמייצר עבורנו getters, setters וכו' בזמן הריצה. ליישומים גדולים יכולים להיות המון המון תלות. חלקם טרנזיטיביים (כלומר, לכל תלות עשויות להיות תלות משלה, וכן הלאה). כתוצאה מכך, התוקפים שמים לב יותר ויותר לתלות בקוד פתוח, מכיוון שהם נמצאים בשימוש קבוע ולקוחות רבים עלולים להיתקל בבעיות בגללן. חשוב לוודא שאין נקודות תורפה ידועות בכל עץ התלות (כן, זה נראה כמו עץ). ישנן מספר דרכים לעשות זאת.

השתמש ב-Snyk לניטור תלות

Snyk בודק את כל התלות בפרויקט ומסמן פגיעויות ידועות. אתה יכול להירשם ב-Snyk ולייבא את הפרויקטים שלך דרך GitHub. אבטחה ב-Java: שיטות עבודה מומלצות - 3כמו כן, כפי שניתן לראות מהתמונה למעלה, אם פגיעות תוקנה בגרסה חדשה יותר, אז Snyk יציע את התיקון ויצור בקשת משיכה. אתה יכול להשתמש בו בחינם עבור פרויקטים בקוד פתוח. פרויקטים נסרקים במרווחי זמן קבועים, למשל פעם בשבוע, פעם בחודש. נרשמתי והוספתי את כל המאגרים הציבוריים שלי לסריקת Snyk (אין בזה שום דבר מסוכן, מכיוון שהם כבר ציבוריים לכולם). לאחר מכן Snyk הראה את תוצאת הסריקה: אבטחה ב-Java: שיטות עבודה מומלצות - 4ואחרי זמן מה, Snyk-bot הכין מספר בקשות משיכה בפרויקטים שבהם יש צורך לעדכן תלות: אבטחה ב-Java: שיטות עבודה מומלצות - 5וגם: אבטחה ב-Java: שיטות עבודה מומלצות - 6זהו כלי נהדר לאיתור נקודות תורפה ולניטור עדכונים עבור גרסאות חדשות.

השתמש במעבדת האבטחה של GitHub

כל מי שעובד על GitHub יכול לנצל את הכלים המובנים שלו. אתה יכול לקרוא עוד על גישה זו בפוסט הבלוג שלהם שכותרתו הכריזה על GitHub Security Lab . הכלי הזה, כמובן, פשוט יותר מסניק, אבל בהחלט לא כדאי להזניח אותו. יתרה מכך, מספר הפגיעויות הידועות רק יגדל, כך שגם Snyk וגם GitHub Security Lab ימשיכו להתרחב ולהשתפר.

הפעל את Sonatype DepShield

אם אתה משתמש ב-GitHub כדי לאחסן את המאגרים שלך, אתה יכול להוסיף את Sonatype DepShield, אחד מהיישומים ב-MarketPlace, לפרויקטים שלך. זה יכול לשמש גם לסריקת פרויקטים לאיתור תלות. יתר על כן, אם הוא ימצא משהו, תיווצר בעיית GitHub עם תיאור מתאים כפי שמוצג להלן:אבטחה ב-Java: שיטות עבודה מומלצות - 7

4. טפל בנתונים חסויים בזהירות

לחילופין אנו עשויים להשתמש בביטוי "נתונים רגישים". הדלפת מידע אישי של לקוח, מספרי כרטיסי אשראי ומידע רגיש אחר עלולה לגרום לנזק בלתי הפיך. קודם כל, תסתכל מקרוב על עיצוב האפליקציה שלך וקבע אם אתה באמת צריך נתונים כאלה או אחרים. אולי אתה בעצם לא צריך חלק מהנתונים שיש לך - נתונים שנוספו לעתיד שלא הגיע וספק אם יגיע. בנוסף, רבים מכם מדליפים בטעות נתונים כאלה דרך רישום. דרך קלה למנוע כניסת נתונים רגישים ליומנים שלך היא לשפשף את שיטות toString() של ישויות תחום (כגון משתמש, תלמיד, מורה וכו'). זה ימנע ממך להוציא בטעות שדות חסויים. אם אתה משתמש ב-Lombok כדי ליצור את השיטה toString() תוכל להשתמש בביאור @ToString.Exclude כדי למנוע שימוש בשדה בפלט של השיטה toString() . כמו כן, היזהר מאוד בעת שליחת נתונים לעולם החיצון. נניח שיש לנו נקודת קצה HTTP שמציגה את שמות כל המשתמשים. אין צורך להציג מזהה פנימי ייחודי של משתמש. למה? מכיוון שתוקף יכול להשתמש בו כדי להשיג מידע אחר ורגיש יותר על המשתמש. לדוגמה, אם אתה משתמש בג'קסון כדי להפוך את POJO ל-/מ- JSON בהמשכה/לבטל את הרצף, אז אתה יכול להשתמש בהערות @JsonIgnore ו- @JsonIgnoreProperties כדי למנוע הסדרה/דה-סידריאליזציה של שדות ספציפיים. באופן כללי, אתה צריך להשתמש בשיעורי POJO שונים במקומות שונים. מה זה אומר?
  1. בעבודה עם מסד נתונים, השתמש בסוג אחד של POJO (ישות).
  2. כאשר עובדים עם לוגיקה עסקית, המרת ישות למודל.
  3. בעת עבודה עם העולם החיצון ושליחת בקשות HTTP, השתמש בישויות שונות (DTOs).
כך ניתן להגדיר בצורה ברורה אילו שדות יהיו גלויים מבחוץ ואילו לא.

השתמש באלגוריתמי הצפנה וגיבוב חזקים

הנתונים הסודיים של הלקוחות חייבים להיות מאוחסנים בצורה מאובטחת. לשם כך, עלינו להשתמש בהצפנה. בהתאם למשימה, עליך להחליט באיזה סוג של הצפנה להשתמש. בנוסף, הצפנה חזקה יותר לוקחת יותר זמן, אז שוב אתה צריך לשקול עד כמה הצורך בה מצדיק את הזמן המושקע בה. כמובן, אתה יכול לכתוב אלגוריתם הצפנה בעצמך. אבל זה מיותר. ניתן להשתמש בפתרונות הקיימים בתחום זה. לדוגמה, Google Tink :
<!-- https://mvnrepository.com/artifact/com.google.crypto.tink/tink -->
<dependency>
   <groupid>com.google.crypto.tink</groupid>
   <artifactid>tink</artifactid>
   <version>1.3.0</version>
</dependency>
בוא נראה מה לעשות, באמצעות דוגמה זו הכוללת הצפנה ופענוח:
private static void encryptDecryptExample() {
   AeadConfig.register();
   KeysetHandle handle = KeysetHandle.generateNew(AeadKeyTemplates.AES128_CTR_HMAC_SHA256);

   String plaintext = "Elvis lives!";
   String aad = "Buddy Holly";

   Aead aead = handle.getPrimitive(Aead.class);
   byte[] encrypted = aead.encrypt(plaintext.getBytes(), aad.getBytes());
   String encryptedString = Base64.getEncoder().encodeToString(encrypted);
   System.out.println(encryptedString);

   byte[] decrypted = aead.decrypt(Base64.getDecoder().decode(encrypted), aad.getBytes());
   System.out.println(new String(decrypted));
}

הצפנת סיסמאות

עבור משימה זו, הכי בטוח להשתמש בהצפנה אסימטרית. למה? כי האפליקציה לא באמת צריכה לפענח סיסמאות. זו הגישה הסטנדרטית. במציאות, כאשר משתמש מזין סיסמה, המערכת מצפינה אותה ומשווה אותה למה שקיים בחנות הסיסמאות. מתבצע אותו תהליך הצפנה, כך שנוכל לצפות שהם יתאימו, אם תזין את הסיסמה הנכונה כמובן :) BCrypt ו-SCrypt מתאימות כאן. שתיהן פונקציות חד-כיווניות (hashs קריפטוגרפיים) עם אלגוריתמים מורכבים מבחינה חישובית שלוקחים זמן רב. זה בדיוק מה שאנחנו צריכים, מכיוון שהחישובים הישירים יימשכו לנצח (טוב, הרבה מאוד זמן). Spring Security תומך במגוון שלם של אלגוריתמים. אנו יכולים להשתמש ב- SCryptPasswordEncoder ו- BCryptPasswordEncoder . מה שנחשב כיום לאלגוריתם הצפנה חזק עשוי להיחשב חלש בשנה הבאה. כתוצאה מכך, אנו מסיקים שעלינו לבדוק באופן קבוע את האלגוריתמים בהם אנו משתמשים ולעדכן, לפי הצורך, את הספריות המכילות את אלגוריתמי ההצפנה.

במקום מסקנה

היום דיברנו על אבטחה ומטבע הדברים, הרבה דברים נשארו מאחורי הקלעים. זה עתה פתחתי עבורך את הדלת לעולם חדש, עולם שיש לו חיים משלו. ביטחון הוא בדיוק כמו פוליטיקה: אם אתה לא עסוק בפוליטיקה, הפוליטיקה תעסוק בך. באופן מסורתי אני מציע לך לעקוב אחריי בחשבון GitHub . שם אני מפרסם את היצירות שלי הכוללות טכנולוגיות שונות שאני לומד ומיישם בעבודה.

קישורים שימושיים

  1. Guru99: הדרכה להזרקת SQL
  2. אורקל: Java Security Resource Center
  3. אורקל: הנחיות קידוד מאובטח עבור Java SE
  4. Baeldung: היסודות של אבטחת Java
  5. בינוני: 10 טיפים לחיזוק אבטחת Java שלך
  6. Snyk: 10 שיטות עבודה מומלצות לאבטחת Java
  7. GitHub: הכרזה על GitHub Security Lab: אבטחת הקוד של העולם, ביחד
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION