Java 3 - 2025

Week 7

XSS attacks

  • Cross-Site Scripting (XSS) attacks occur when a user enters JavaScript into form fields that get saved to a database.

  • Unescaped script strings are rendered as JavaScript when read.

  • Malicious users can for example, write scripts that display buttons or other content that, when clicked, redirects the user to a different website.

  • They can also write scripts to give the attacker access to session data or other sensitive information retained by a browser.

  • Run the program and enter these as the text for your first and last names:

    • <a href="/path/to/file.pdf download="virus.exe">hacked.com</a>

    • <script>let i = 0; while(i<100){open();i++;}</script>

  • Notice how a JavaScript alert pops up. View the source code and see how this code is actually embedded within your HTML.

  • Read more about XSS attacks on the OWASP website.

XSS attacks

  • To protect our site and our users, we can validate input not to allow certain characters to be typed (like <, >, and "), or we can encode user input.

  • To prevent XSS Attacks, add the fn:escapeXML() method inside any EL tag anywhere you are displaying content read in from user input.

  • For example, replace ${activeUser.firstName} with:
    ${fn:escapeXml(activeUser.firstName)}

  • Run the project again. This time, instead of <script> tags appearing in your HTML, the code will look something like this:
    &lt;script&gt;alert(&#034;This could be a Cross-Site Scripting attack&#034;);&lt;/script&gt;!

    • < becomes &lt;, > becomes &gt;,
      & becomes &amp;, and " becomes &quot;

XSS attacks

  • Repeat on all JSPs that display data from user input.

    • top.jspf (flash messages)

    • admin-users.jsp

    • admin-vendors.jsp

    • admin-products.jsp

  • Write a method to convert or remove unauthorized characters from Strings before inserting or updating database records.

Other EL Functions

  • In the webapp folder, create a JSP called fn-test.jsp.

  • Add this code.

  • Visit the JSP directly.

<c:set var="test" value="Kirkwood Eagles"></c:set>
<div class="container">
    <h2>${test}</h2>
    <ul>
        <li>Contains "Kirkwood": ${fn:contains(test, "Kirkwood")}</li>
        <li>Contains "kirkwood" regardless of capitalization: ${fn:containsIgnoreCase(test, "kirkwood")}</li>
        <li>To lowercase: ${fn:toLowerCase(test)}</li>
        <li>To uppercase: ${fn:toUpperCase(test)}</li>
      	<li>Starts with "Kirkwood": ${fn:startsWith(fn:toLowerCase(test), "kirkwood")}</li>
        <li>Ends with "Kirkwood": ${fn:endsWith(fn:toLowerCase(test), "kirkwood")}</li>
        <li>Starting index of "Kirkwood": ${fn:indexOf(fn:toLowerCase(test), "kirkwood")}</li>
        <li>Length: ${fn:length(test)}</li>
        <li>"wood" changed to "land": ${fn:replace(fn:toLowerCase(test), "wood", "land")}</li>
        <li>Starts with "K": ${fn:startsWith(fn:toLowerCase(test), "k")}</li>
        <li>First 4 characters: ${fn:substring(test, 0, 4)}</li>
        <li>Characters after "Kirk": ${fn:substringAfter(fn:toLowerCase(test), "kirk")}</li>
        <li>Characters before "wood": ${fn:substringBefore(fn:toLowerCase(test), "wood")}</li>
        <li>White space removed from both ends: ${fn:trim(test)}</li>
        <c:set var="numWords" value="${fn:split(test, ' ')}" /> <!--Splits a string into an array of substrings-->
        <li>Number of words: ${fn:length(numWords)}</li> <!--Then finds the length of the array.-->
        <li>Words joined with a forward slash: ${fn:join(numWords, "/")}</li>
    </ul>
</div>

Expression Language (EL) Functions

  • c:set() Sets the result of an expression evaluation in a 'scope'. The default scope is the Page scope.
  • fn:contains() Tests if an input string contains the specified substring.
  • fn:containsIgnoreCase() Tests if an input string contains the specified substring in a case insensitive way.
  • fn:endsWith() Tests if an input string ends with the specified suffix.
  • fn:indexOf() Returns the index withing a string of the first occurrence of a specified substring.
  • fn:join() Joins all elements of an array into a string.
  • fn:length() Returns the number of items in a collection, or the number of characters in a string.
  • fn:replace() Returns a string resulting from replacing in an input string all occurrences with a given string.
  • fn:split() Splits a string into an array of substrings.
  • fn:startsWith() Tests if an input string starts with the specified prefix.
  • fn:substring() Returns a subset of a string.
  • fn:substringAfter() Returns a subset of a string following a specific substring.
  • fn:substringBefore() Returns a subset of a string before a specific substring.
  • fn:toLowerCase() Converts all of the characters of a string to lower case.
  • fn:toUpperCase() Converts all of the characters of a string to upper case.
  • fn:trim() Removes white spaces from both ends of a string.

Expression Language (EL) Functions

DeleteAccount Servlet

  • Create a new servlet called "DeleteAccount". Add this code.
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

@WebServlet("/delete-account")
public class DeleteAccount extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        HttpSession session = req.getSession();
        User user = (User)session.getAttribute("activeUser");
        if(user == null) {
        	resp.sendRedirect(resp.encodeRedirectURL(req.getContextPath() + "/login?redirect=delete-account"));
            return;
        }
        req.setAttribute("pageTitle", "Delete Account");
        req.getRequestDispatcher("WEB-INF/delete-account.jsp").forward(req, resp);
    }
}

delete-account.jsp

  • Create a new JSP called "delete-account.jsp". Add this code.
<main>
    <jsp:include page="/WEB-INF/edit-profile-header.jsp"></jsp:include>

    <section class="pt-0">
        <div class="container">
            <div class="row">

                <jsp:include page="/WEB-INF/left-sidebar.jsp"></jsp:include>

                <!-- Main content START -->
                <div class="col-xl-9">
                    <!-- Title and select START -->
                    <div class="card border bg-transparent rounded-3 mb-0">
                        <!-- Card header -->
                        <div class="card-header bg-transparent border-bottom">
                            <h3 class="card-header-title mb-0">Delete Account</h3>
                        </div>
                        <!-- Card body -->
                        <div class="card-body">
                            <h6>If you delete your account, you will lose your all data.</h6>
                            <form method="POST" action="${appURL}/delete-account">
                                <!-- Email id -->
                                <div class="col-md-6 my-4">
                                    <label class="form-label" for="email">Enter your email to confirm account deletion</label>
                                    <input class="form-control <c:if test="${not empty results.emailError}">is-invalid</c:if>" type="text" id="email" name="email" value="${email}">
                                    <c:if test="${not empty results.emailError }"><div class="invalid-feedback">${results.emailError}</div></c:if>
                                </div>

                                <button type="submit" class="btn btn-danger mb-0">Delete my account</button>
                            </form>
                        </div>
                    </div>
                    <!-- Title and select END -->
                </div>
                <!-- Main content END -->
            </div><!-- Row END -->
        </div>
    </section>
</main>

Delete User

CREATE PROCEDURE sp_delete_user(IN p_user_id int)
BEGIN
    DELETE FROM user WHERE user_id = p_user_id;
END;
  • Create/Update a stored procedure to delete a user

UserDAO

public static void delete(User user) {
    try (Connection connection = getConnection()) {
        if (connection != null) {
            try (CallableStatement statement = connection.prepareCall("{CALL sp_delete_user(?)}")) {
                statement.setInt(1, user.getId());
                statement.execute();
            }
        }
    } catch (SQLException e) {
        throw new RuntimeException(e);
    }
}
  • Create a delete method to delete a user based on their id.Create a delete method to delete a user based on their id.

DeleteAccount Servlet doPost

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String email = req.getParameter("email");

    HttpSession session = req.getSession();
    User activeUser = (User)session.getAttribute("activeUser");
    
    boolean errorFound = false;
    if(!email.equals(activeUser.getEmail())) {
    	errorFound = true;
        req.setAttribute("emailError", "The value you entered is not the same as <b>'" + activeUser.getEmail() + "'</b>.");
    }

    if(!errorFound) {
        UserDAO.delete(activeUser);
        session.invalidate();
        session = req.getSession();
        session.setAttribute("flashMessageWarning", "Your account has been deleted.");
        resp.sendRedirect(resp.encodeRedirectURL(req.getContextPath() + "/")); // Redirects to the home page
        return;
    }

    req.setAttribute("pageTitle", "Delete Account");
    req.getRequestDispatcher("WEB-INF/delete-account.jsp").forward(req, resp);
}
  • Create a doPost method. Add this code.
  • Run the program and test the delete functionality.

DeleteAccount Servlet doPost

  • 2026 - In 2025, many student's programs did this...
  • I entered an incorrect, but existing email address, and your form deleted my account. Only delete it if the email address entered matches the one stored in the User session attribute.

fmt:formatNumber

  • In Java 2, you briefly learned about the fmt taglib directive. At the beginning of the semester, we added this line to top.jspf.
    <%@ taglib prefix="fmt" uri="jakarta.tags.fmt" %>
  • The example from Java 2 can be found in the admin-product.jsp and shop.jsp files. We are using it to format product prices (double) as currency.
    <fmt:formatNumber value="${product.price}" type="currency" />
  • Run the program and view the public-facing Shop page.
  • Log in as an admin user, and view the Product admin page.
  • The type value can also be "number" or "percent"

Instant to Date

  • The fmt taglib directive also supports formatting dates.
  • This requires a getter method that returns a java.util.Date object.
  • Note that our Order class currently has an orderDate instance variable declared as an Instant object
  • Note that the Date class has a static method called from() that takes an Instant object and converts it into a Date object.
  • The java.sql.Date class has a valueOf() method that takes a LocalDate object and returns a Date object.
    • A LocalDate would be good if you wanted to store something like a User's birthday or something where the time of day is not important.
  • Add this method to the Order class.
public Date getOrderDateDate() {
    return Date.from(orderDate);
}

fmt:formatDate Date only

  • Open the admin-orders.jsp file. Update the orderDate expression with the fmt:formatDate tag.
    <fmt:formatDate value="${order.orderDateDate}" dateStyle="full" />
  • The dateStyle can be "short" (1/1/20), "medium" (Jan 1, 2020), "long" (January 1, 2020), or "full" (Wednesday, January 1, 2020)

fmt:formatDate Date and Time

  • Open the edit-profile-header.jspf file.
  • Replace the "Member since" text with this code to format the Instant to a Date:
    Member since: <fmt:formatDate value="${activeUser.createdAtDate}" type="date" dateStyle="long" />
  • Note the type attribute is set to "date"
  • Add this method to the User class.
public Date getCreatedAtDate() {
    return Date.from(createdAt);
}

fmt:formatDate Date and Time

  • Add this code above the h4 "Good morning" text to get the current date and time.
    <jsp:useBean id="now" class="java.util.Date" scope="page" />
  • Replace the current date/time text with this code:
    Current date/time: <fmt:formatDate value="${now}" type="both" dateStyle="full" timeStyle="long" />
  • ​Note the type attribute is set to "both". This allows me to use the dateStyle and timeStyle attributes.
  • This tag is written to use the default locale and time zone. A timeZone attribute can be added to specify a different time zone. The time zone will display with the "long" or "full" timeStyle

fmt:formatDate pattern

  • A custom format can be used with the pattern attribute. This can be used to display hours, minutes, seconds, etc.
  • pattern="MMMM d, YYYY h:mm a z"
  • Note that the time zone will be based on the server's settings.
  • If you get an error when running the program, try disabling the errorHandler in the web.xml file.

fmt:formatNumber

  • In the admin-product.jsp and shop.jsp views, I have already demonstrated the fmt:formatNumber tag with currency.
  • Add this code somewhere to demonstrate number formatting:
    <fmt:formatNumber type="number" value="12345.6789" maxFractionDigits="1" />
  • By default, numbers round to 3 digits and group numbers with commas based on the locale.
  • For rounding accuracy, the maxFractionDigits attribute specifies the maximum number of digits after the decimal separator.
  • There is also a minFractionDigits attribute to pad zeroes to the end of the decimal portion of the number.
  • The groupingUsed attribute can turn on/off comma separators using the values true and false.

fmt:formatNumber Percentages

  • Add this code somewhere to demonstrate percent formatting:
    <fmt:formatNumber type="percent" value="0.6789" maxFractionDigits="2" />
  • A percent formats a decimal number as a percentage.
  • The maxFractionDigits attribute can be used to specify the number of digits after the decimal separator
  • Note that 67.89% and 0.6789 are equivalent. 67.89 would result in 6789%.

2026

  • Require Good Morning, Good Afternoon, Good Evening
  • Tell students you will not grade assignment 12 until assignment 11 is fully complete.

Get User By ID

CREATE PROCEDURE sp_get_user_by_id(IN p_user_id int)
BEGIN
    SELECT user_id, first_name, last_name, email, phone, password, language, status, privileges, created_at, timezone
    FROM user
    WHERE user_id = p_user_id;
END
  • Create a stored procedure to get a user by their id.

Java 3 - Week 7

By Marc Hauschildt

Java 3 - Week 7

  • 297