null Bachaav Session | Secure Coding in Java
Upcoming SlideShare
Loading in...5
×
 

null Bachaav Session | Secure Coding in Java

on

  • 1,457 views

null Bachaav Session

null Bachaav Session

Statistics

Views

Total Views
1,457
Views on SlideShare
1,457
Embed Views
0

Actions

Likes
0
Downloads
13
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

CC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike License

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    null Bachaav Session | Secure Coding in Java null Bachaav Session | Secure Coding in Java Presentation Transcript

    • Secure Coding In Java By : Abhishek Nigam Cybage Software Pvt. Ltd.
    • JAVA
    • ● Java is a computer programming language that is concurrent, class­ based, object­oriented, and specifically designed to have as few  implementation dependencies as possible ●  It is intended to let application developers "write once, run  anywhere" (WORA), meaning that code that runs on one platform  does not need to be recompiled to run on another.  ● Java applications are typically compiled to bytecode (class file) that  can run on any Java virtual machine (JVM) regardless of computer  architecture. ●  Java is, as of 2014, one of the most popular programming languages  in use, particularly for client­server web applications, with a reported  9 million developers. ●  Java was originally developed by James Gosling at Sun  Microsystems (which has since merged into Oracle Corporation) and  released in 1995 as a core component of Sun Microsystems' Java  platform. 
    • ● There were five primary goals in the creation of the Java language: a.    It should be "simple, object­oriented and familiar" b.   It should be "robust and secure" c.    It should be "architecture­neutral and portable" d.    It should execute with "high performance" e.    It should be "interpreted, threaded, and dynamic" Java is a relatively secure language. It has no explicit pointer manipulation;  array and string bounds are automatically checked; attempts at referencing a  null pointer are trapped; the arithmetic operations are well defined and  platform independent, as are the type conversions. The built­in bytecode  verifier ensures that these checks are always in place.
    • JIT(Just­In­Time) ● A common implementation of JIT compilation is to first have AOT  compilation to bytecode (virtual machine code), known as bytecode  compilation, and then have JIT compilation to machine code  (dynamic compilation), rather than interpretation of the bytecode. ● This improves the runtime performance compared to interpretation. ● JIT compilers translate continuously, as with interpreters, but  caching of compiled code minimizes lag on future execution of the  same code during a given run.
    • Security Manager ● The security manager is a class that allows applications to implement a  security policy.  ● It allows an application to determine, before performing a possibly unsafe or  sensitive operation, what the operation is and whether it is being attempted  in a security context that allows the operation to be performed.  ●  Security manager routine simply returns if the operation is permitted, but  throws a SecurityException if the operation is not permitted.  ●  The special method checkPermission(java.security.Permission) determines  whether an access request indicated by a specified permission should be  granted or denied. The default implementation calls “AccessController.checkPermission(perm)”
    • ● The policy configuration file(s) for a JDK or JRE installation specifies  what permissions (which types of system resource accesses) are  granted to code from a specified code source, and executed as a  specified principal. ● For an applet (or an application running under a security manager)  to be allowed to perform secured actions (such as reading or writing  a file), the applet (or application) must be granted permission for  that particular action. In the Policy reference implementation, that  permission must be granted by a grant entry in a policy  configuration file.
    • Object Orientation (OBJ)
    • Limit extensibility of classes and methods with  invariants ● Many classes also offer invariants, which are guarantees made about the state of their  objects' fields upon the completion of any of their methods ● A subclass can fail to satisfy the invariants promised to clients by its superclass, and it  can break the internal invariants on which the superclass relies. For instance, an  immutable class that lacks the final qualifier can be extended by a malicious subclass. ●  To mitigate these risks, classes must be declared final by default. Developers should  permit extensibility only when there is a perceived need for it and must. ● The java.math.BigInteger class is itself an example of noncompliant code. It is non­final  and consequently extendable. This can be a problem when operating on an instance  of BigInteger that was obtained from an untrusted client.
    • Limit extensibility of classes and methods with  invariants ● Many classes also offer invariants, which are guarantees made about the state of their  objects' fields upon the completion of any of their methods ● A subclass can fail to satisfy the invariants promised to clients by its superclass, and it  can break the internal invariants on which the superclass relies. For instance, an  immutable class that lacks the final qualifier can be extended by a malicious subclass. ●  To mitigate these risks, classes must be declared final by default. Developers should  permit extensibility only when there is a perceived need for it and must. ● The java.math.BigInteger class is itself an example of noncompliant code. It is non­final  and consequently extendable. This can be a problem when operating on an instance  of BigInteger that was obtained from an untrusted client.
    • Declare data members as private and provide  accessible wrapper methods ● It is difficult to control how data members declared public or protected are accessed. Attackers can manipulate such members in unexpected ways. As a result data members must be declared private.
    • Do not use public static nonfinal variables ● Client code can trivially access public static fields. Neither reads nor  writes to such variables are checked by a security manager. ● New values cannot be validated programmatically before they are  stored in these fields. ● Improper use of public static fields can also result in type­safety  issues.  ●  Untrusted code can supply an unexpected subtype with malicious  methods when the variable is defined to be of a more general type,  such as java.lang.Object 
    • Be wary of letting constructors throw exceptions ● An object is partially initialized if a constructor has begun building  the object but has not finished. As long as the object is not fully  initialized, it must be hidden from other classes. ● There are three common approaches to dealing with the problem of  partially initialized objects: ● Exception in constructor. One approach is to throw an exception in  the object's constructor. Unfortunately, an attacker can maliciously  obtain the instance of such an object.  ● Final field. Declaring the variable that is initialized to the object as  final prevents the object from being partially initialized.  ●
    • Runtime Environment (ENV)
    • Do not sign code that performs only unprivileged  operations ● Java applets can escape the default sandbox restrictions when signed. ● For example, signed Java applets. When a certificate is verified, on  widely used platforms, the user is presented with a security dialog in  which the option "Always trust the content from the publisher" is  selected by default. ● An attacker can take advantage of this mechanism by exploiting  vulnerable code signed by the trusted organization. ● Oracle has deprecated the use of unsigned applets, and will cease to  support them soon.  ● Since Java 1.7.0 update 25, Oracle has provided mechanisms to allow  applets to be signed, and yet run without full permissions. This enables  applets that are today unsigned to continue to run in a security sandbox,  despite being signed.
    • Place all security­sensitive code in a single JAR  and sign and seal it ● If an attacker can link security­sensitive code with malicious code, he  or she can indirectly cause incorrect behavior. This is called a mix­ and­match attack. ● Privileged code may use a class that exists in an untrusted container  and performs only unprivileged operations. ● If the attacker were to replace the class in the untrusted container  with a malicious class, the trusted code might receive incorrect  results and misbehave at the discretion of the malicious code. ● “A package sealed within a JAR specifies that all classes defined in  that package must originate from the same JAR. Otherwise, a  SecurityException is thrown.” 
    •  Do not trust the values of environment variables ● Programs that execute in a more trusted domain than their environment  must assume that the values of environment variables are untrusted and  must sanitize and validate any environment variable values before use. ● The default values of system properties are set by the Java Virtual Machine  (JVM) upon startup and can be considered trusted.  ● However, they may be overridden by properties from untrusted sources,  such as a configuration file. System properties from untrusted sources must  be sanitized and validated before use. ● An attacker can essentially control all environment variables that enter a  program using a mechanism such as the java.lang.ProcessBuilder class.
    • Do not grant dangerous combinations of  permissions ● “All Permission” :­ The permission java.security.AllPermission grants all  possible permissions to code. ● Code is typically granted AllPermission via the security policy file  ● “ReflectPermission, suppressAccessChecks” :­ Granting ReflectPermission  on the target suppressAccessChecks suppresses all standard Java language  access checks when the permitted class attempts to operate on package­ private, protected, or private members of another class. ● The permitted class can obtain permissions to examine any field or invoke  any method belonging to an arbitrary class. ● “RuntimePermission, createClassLoader” :­The permission  java.lang.RuntimePermission applied to target createClassLoader grants code  the permission to create a ClassLoader object.  ● This is extremely dangerous because malicious code can create its own  custom class loader and load classes by assigning them arbitrary permissions.
    • Do not disable bytecode verification ● When Java source code is compiled, it is converted into bytecode,  saved in one or more class files, and executed by the JVM. Java class  files may be compiled on one machine and executed on another  machine. ● The Java bytecode verifier is an internal component of the JVM that  is responsible for detecting nonconforming Java bytecode. ● The bytecode verifier must not be suppressed. ● To supress bytecode verifier :­ “java ­Xverify:none ApplicationName”
    • Do not deploy an application that can be remotely  monitored ● The JVMTI (JVM Tool Interface)contains extensive facilities to learn  about the internals of a running JVM, including facilities to monitor  and modify a running Java program. ● The JVMTI profiling tools can also measure the time that a thread  takes to execute, leaving applications vulnerable to timing attacks. ● The JVMTI is always enabled, and JVMTI agents may run under the  default security manager without requiring any permissions to be  granted. ● The Java Platform Debugger Architecture (JPDA) builds on the  JVMTI and provides high­level facilities for debugging Java systems  while they are running  ● The JPDA facilities are similar to the reflection API
    • Production code must not contain debugging entry  points ● A common development practice is to add "back door" code  specifically designed for debugging or testing purposes that is not  intended to be shipped or deployed with the application.  ●  These back door entry points create security risks because they are  not considered during design or testing and fall outside of the  expected operating conditions of the application.
    • Methods(MET)
    • Validate method arguments ● This practice ensures that operations on the method's parameters  yield valid results. Failure to validate method arguments can result  in incorrect calculations, runtime exceptions, violation of class  invariants, and inconsistent object state. ● Caller validation of arguments can result in faster code because the  caller may be aware of invariants that prevent invalid values from  being passed. 
    • Do not use deprecated or obsolete classes or  methods ● Java also provides a @deprecated annotation to indicate the  deprecation of specific fields, methods, and classes.  ● For instance, many methods of java.util.Date, such as Date.getYear(),  have been explicitly deprecated. ● E.g of deprecated methods :­ java.lang.Thread.run(),  java.lang.Thread.stop(), java.lang.ThreadGroup (many methods).
    • Methods that perform a security check must be  declared private or final ● Non­final member methods that perform security checks can be  compromised when a malicious subclass overrides the methods and  omits the checks. 
    •  Do not increase the accessibility of overridden or  hidden methods ● Increasing the accessibility of overridden or hidden methods permits  a malicious subclass to offer wider access to the restricted method  than was originally intended.
    • Ensure that constructors do not call overridable  methods ● Invocation of an overridable method during object construction may  result in the use of uninitialized data, leading to runtime exceptions  or to unanticipated outcomes. ● Calling overridable methods from constructors can also leak the this  reference before object construction is complete, potentially  exposing uninitialized or inconsistent data to other threads. ● Constructors must invoke only methods that are final or private.
    • Do not invoke overridable methods in clone() ● A malicious subclass could override the method and affect the  behavior of the clone() method. ● A trusted subclass could observe (and potentially modify) the cloned  object in a partially initialized state before its construction has  concluded. ● The subclass could leave the clone, the object being cloned, or both  in an inconsistent state. Consequently, clone() methods may invoke  only methods that are final or private.
    • ● By default, java cloning is ‘field by field copy’ i.e. as the Object class  does not have idea about the structure of class on which clone()  method will be invoked. So, JVM when called for cloning, do  following things: 1) If the class has only primitive data type members then a  completely new copy of the object will be created and the reference  to the new object copy will be returned. 2) If the class contains members of any class type then only the  object references to those members are copied and hence the  member references in both the original object as well as the cloned  object refer to the same object.
    • Never declare a class method that hides a method  declared in a superclass or superinterface ● When a class declares a static method m, the declaration of m hides  any method m', where the signature of m is a subsignature of the  signature of m' and the declaration of m' is both in the superclasses  and superinterfaces of the declaring class and also would otherwise  be accessible to code in the declaring class. ● Hiding and overriding differ in the determination of which method is  invoked from a call site.
    • Classes that define an equals() method must also  define a hashCode() method ● Classes that override the Object.equals() method must also override  the Object.hashCode() method.  ● The java.lang.Object class requires that any two objects that compare  equal using the equals() method must produce the same integer  result when the hashCode() method is invoked on the objects  ● The equals() method is used to determine logical equivalence  between object instances. ● The contract between hashCode and equals method:­   “if two objects are equal, that is obj1.equals(obj2) is true then,  obj1.hashCode() and obj2.hashCode() must return same integer” ● hashCode() and getClass() are  native methods.
    • Ensure that keys used in comparison operations  are immutable ● Objects that serve as keys in ordered sets and maps should be  immutable. When some fields must be mutable, the equals(),  hashCode(), and compareTo() methods must consider only  immutable state when comparing objects. ● The documentation of java.util.Interface Set<E> and  java.util.Interface Map<K,V> warns against this.
    • ● great care must be exercised when mutable objects are used as map  keys. The behavior of a map is not specified if the value of an object  is changed in a manner that affects equals comparisons while the  object is a key in the map.  ● A special case of this prohibition is that it is not permissible for a  map to contain itself as a key. While it is permissible for a map to  contain itself as a value, extreme caution is advised: the equals and  hashCode methods are no longer well defined on such a map.
    • Do not use finalizers ● The garbage collector invokes object finalizer methods after it determines that  the object is unreachable but before it reclaims the object's storage. Execution of  the finalizer provides an opportunity to release resources such as open streams,  files, and network connections that might not otherwise be released  automatically through the normal action of the garbage collector. ● There is no fixed time at which finalizers must be executed because this depends  on the JVM. ● The only guarantee is that any finalizer method that executes will do so  sometime after the associated object has become unreachable (detected during  the first cycle of garbage collection) and sometime before the garbage collector  reclaims the associated object's storage (during the garbage collector's second  cycle). ● The JVM may terminate without invoking the finalizer on some or all  unreachable objects.
    • ● Uncaught exceptions thrown during finalization are ignored. When  an exception thrown in a finalizer propagates beyond the finalize()  method, the process itself immediately stops and consequently fails  to accomplish its sole purpose. ● Coding errors that result in memory leaks can cause objects to  incorrectly remain reachable. ● A programmer can unintentionally resurrect an object's reference in  the finalize() method. When this occurs, the garbage collector must  determine yet again whether the object is free to be deallocated.  Further, because the finalize() method has executed once, the  garbage collector cannot invoke it a second time.
    • ● Finalizers increase garbage­collection time and introduce space overheads. ● Use of finalizers can introduce synchronization issues even when the  remainder of the program is single­threaded. ● Use of locks or other synchronization­based mechanisms within a finalizer  can cause deadlock or starvation. ● Exceptions :­ Finalizers may be used when working with native code because the  garbage collector cannot reclaim memory used by code written in  another language and because the lifetime of the object is often  unknown. Again, the native process must not perform any critical jobs  that require immediate resource deallocation.
    • Thread API
    • Do not invoke Thread.run() ● Invoking the Thread.start() method instructs the Java runtime to  start executing the thread's run() method using the started thread ● When a Thread object's run() method is invoked directly, the  statements in the run() method are executed by the current thread  rather than by the newly created thread. ● If the Thread object was constructed by instantiating a subclass of  Thread that fails to override the run() method ,then any calls to the  subclass's run() method would invoke Thread.run(), which does  nothing. ● Exceptions :­ The run() method may be directly invoked during unit  testing. 
    • Do not invoke ThreadGroup methods ● Each thread in Java is assigned to a thread group upon the thread's  creation. These groups are implemented by the  java.lang.ThreadGroup class. When the thread group name is not  specified explicitly, the main default group is assigned by the Java  Virtual Machine. ● Many of the methods of the ThreadGroup class are deprecated (for  example, allowThreadSuspension(), resume(), stop(), and  suspend()). ●  Few ThreadGroup methods are not even thread­safe. 
    • ● ThreadGroup.activeCount() :­ Threads that have never started  nevertheless reside in the thread group and are considered to be  active. The active count is also affected by the presence of certain  system threads. ● The enumerate() method :­ It copies into the specified array every  active thread in this thread group and its subgroups. An application  should use the activeCount method to get an estimate of how big the  array should be. If the array is too short to hold all the threads, the  extra threads are silently ignored. ● Stop() method :­ An application may have to maintain its own list of  the threads it creates because simply inspecting the ThreadGroup  may return library threads that do not terminate and for which join  will not return.
    • Notify all waiting threads rather than a single  thread ● The notify() method wakes up only one thread, with no guarantee  regarding which specific thread is notified. ● Invoking the notify() method is permitted only when all of the  following conditions are met: a.   All waiting threads have identical condition predicates. b.  All threads perform the same set of operations after waking up.  That is, any one thread can be selected to wake up and resume for a  single invocation of notify(). c.    Only one thread is required to wake upon the notification.
    • Ensure that threads performing blocking  operations can be terminated ● Threads and tasks that block on operations involving network or file  I/O must provide callers with an explicit termination mechanism to  prevent DoS vulnerabilities.
    • Do not use Thread.stop() to terminate threads ● The Thread.stop() method causes the thread to immediately throw a  ThreadDeath exception, which usually stops the thread. ● Invoking Thread.stop() results in the release of all locks a thread has  acquired, potentially exposing the objects protected by those locks  when those objects are in an inconsistent state. ● Removing the java.lang.RuntimePermission stopThread permission  from the security policy file prevents threads from being stopped  using the Thread.stop() method. 
    • Exceptional Behavior (ERR)
    • Do not suppress or ignore checked exceptions ● Programmers often suppress checked exceptions by catching  exceptions with an empty or trivial catch block. ● Each catch block must ensure that the program continues only with  valid invariants. ● no part of any expression or statement that occurs in the try block  after the point from which the exception is thrown is evaluated. ● when the client cannot be expected to recover from the underlying  problem, it is good practice to allow the exception to propagate  outwards rather than to catch and suppress the exception.
    •  Do not allow exceptions to expose sensitive  information ● Failure to filter sensitive information when propagating exceptions  often results in information leaks that can assist an attacker's efforts  develop further exploits. ● For example, the FileNotFoundException message reveals information  about the file system layout, and the exception type reveals the  absence of the requested file. ●  In 2004, Schanefeld discovered an exploit for the Opera v7.54 web  browser in which an attacker could use the  sun.security.krb5.Credentials class in an applet as an oracle to  "retrieve the name of the currently logged in user and parse his home  directory from the information which is provided by the thrown  java.security.AccessControlException"
    • ● Common Exceptions which may cause harm :­ a) java.io.FileNotFoundException :­ Underlying file system structure,  user name enumeration b) java.sql.SQLException :­ Database structure, user name enumeration c) java.lang.OutOfMemoryError :­ DoS d) java.lang.StackOverflowError :­ DoS ● Printing the stack trace can also result in unintentionally leaking  information about the structure and state of the process to an attacker. 
    •  Prevent exceptions while logging data ● Exceptions that are thrown while logging is in progress can prevent  successful logging unless special care is taken. ● Failure to account for exceptions during the logging process can  cause security vulnerabilities, such as allowing an attacker to conceal  critical security exceptions by preventing them from being logged. 
    • Restore prior object state on method failure ● Objects in general should — and security­critical objects must — be  maintained in a consistent state even when exceptional conditions  arise. ● Common techniques for maintaining object consistency include a. Input validation (on method arguments, for example) b. Reordering logic so that code that can result in the exceptional  condition executes before the object is modified c. Using rollbacks in the event of failure d. Performing required operations on a temporary copy of the object  and committing changes to the original object only after their  successful completion e. Avoiding the need to modify the object at all
    • Do not complete abruptly from a finally block ● Never use return, break, continue, or throw statements within a  finally block.  ● Statements that cause the finally block to complete abruptly also  cause the try block to complete abruptly and consequently suppress  any exception thrown from the try or catch blocks. 
    • Do not let checked exceptions escape from a  finally block ● Methods invoked from within a finally block can throw an exception.  Failure to catch and handle such exceptions results in the abrupt  termination of the entire try block. ● the transfer of control associated with the exception may prevent  execution of any expressions or statements that occur after the point  in the finally block from which the exception is thrown.
    • Do not throw RuntimeException, Exception, or  Throwable ● Handling these exceptions requires catching RuntimeException. ● throwing a RuntimeException can lead to subtle errors; for example,  a caller cannot examine the exception to determine why it was  thrown and consequently cannot attempt recovery. ● Methods can throw a specific exception subclassed from Exception or  RuntimeException. 
    • Do not catch NullPointerException or any of its  ancestors ● A NullPointerException exception thrown at runtime indicates the  existence of an underlying null pointer dereference that must be  fixed in the application code ● Catching NullPointerException adds significantly more performance  overhead than simply adding the necessary null checks ● When multiple expressions in a try block are capable of throwing a  NullPointerException, it is difficult or impossible to determine which  expression is responsible for the exception ● Programs rarely remain in an expected and usable state after a  NullPointerException has been thrown.
    • Do not allow untrusted code to terminate the JVM ● Invocation of System.exit() terminates the Java Virtual Machine  (JVM), consequently terminating all running programs and threads. ● This can result in denial­of­service (DoS) attacks.  ● A call to System.exit() that is embedded in Java Server Pages (JSP)  code can cause a web server to terminate, preventing further service  for users. ● Programs must prevent both inadvertent and malicious calls to  System.exit().
    • Input Output (FIO)
    • Create files with appropriate access permissions ● File systems use a privileges and permissions model to protect file  access.  ● When a program creates a file with insufficiently restrictive access  permissions, an attacker may read or modify the file before the  program can modify the permissions. ● files must be created with access permissions that prevent  unauthorized file access.
    •  Detect and handle file­related errors ● Java's file­manipulation methods often indicate failure with a return  value instead of throwing an exception. ● Programs that ignore the return values from file operations often fail  to detect that those operations have failed. ● Java programs must check the return values of methods that perform  file I/O.
    • Remove temporary files before termination ● Temporary files can be used to :­ a. share data between processes. b. store auxiliary program data (for example, to preserve memory). c. construct and/or load classes, JAR files, and native libraries  dynamically. ● Removing temporary files when they are no longer required allows  file names and other resources (such as secondary storage) to be  recycled. ● Removing temporary files when they are no longer required allows  file names and other resources (such as secondary storage) to be  recycled. These utilities are themselves frequently vulnerable to file­ based exploits.
    • Release resources when they are no longer needed ●  The garbage collector cannot free non­memory resources such as  open file descriptors and database connections. ● Failing to release such resources can lead to resource exhaustion  attacks. ● Programs can experience resource starvation while waiting for  finalize() to release resources such as Lock or Semaphore objects. ● Output streams may cache object references; such cached objects are  not garbage­collected until after the output stream is closed.
    • Do not operate on untrusted file links ● Multiuser systems allow several users with different privileges to  share a file system. Each user in such an environment must be able  to determine which files are shared and which are private, and each  user must be sure of the results of these decisions. ● Wide variety of file system vulnerabilities can be exploited by an  attacker to gain access to files for which they lack sufficient  privileges, particularly when operating on files that reside in shared  directories in which multiple users may create, move, or delete files. ● A number of file system properties and capabilities can be exploited  by an attacker, one of which is file links.
    • try {   BasicFileAttributes attr = Files.readAttributes(       path, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);    // Check   if (!attr.isRegularFile()) {     System.out.println("Not a regular file");     return;   }
    • Serialization (SER)
    • Do not deviate from the proper signatures of  serialization methods ● private void writeObject(java.io.ObjectOutputStream out) throws  IOException; ● private void readObject(java.io.ObjectInputStream in) throws  IOException, ClassNotFoundException; ● private void readObjectNoData() throws ObjectStreamException;
    • ● Serializable Interface is a marker interface.  ● These methods must be declared private for any serializable class. ● Deviating from these method signatures produces a method that is not  invoked during object serialization or deserialization. ● Serializable does not define the method signatures it requires.  Interfaces allow only public fields and methods, whereas readObject(),  readObjectNoData, and writeObject() must be declared private ● The Java serialization mechanism fails to let the compiler identify an  incorrect method signature for any of these methods.
    • Do not serialize instances of inner classes ● An inner class is a nested class that is not explicitly or implicitly  declared static . Serialization of inner classes (including local and  anonymous classes) is error prone. ● Serializing an inner class declared in a non­static context that  contains implicit non­transient references to enclosing class instances  results in serialization of its associated outer class instance.
    • Do not serialize unencrypted, sensitive data ● serialization allows an object's state to be saved as a sequence of  bytes and then reconstituted at a later time, it provides no  mechanism to protect the serialized data. ● An attacker who gains access to the serialized data can use it to  discover sensitive information and to determine implementation  details of the objects. ● An attacker can also modify the serialized data in an attempt to  compromise the system when the malicious data is deserialized. ● Sensitive data that should never be serialized include cryptographic  keys, digital certificates, and classes that may hold references to  sensitive data at the time of serialization.