精华内容
下载资源
问答
  • java项目安全性问题

    2021-03-06 14:10:57
    java项目安全性问题 一、登录爆破 问题: 登录无错误限制,可以无限制的错误尝试登录 解决思路: 增加登录错误计数,达到一定数量就禁止用户登录一定时间 二、密码安全 问题: 用户密码过于简单,容易...

    java项目安全性问题

    一、登录爆破

    • 问题:
      1. 登录无错误限制,可以无限制的错误尝试登录
    • 解决思路:
      1. 增加登录错误计数,达到一定数量就禁止用户登录一定时间

    二、密码安全

    • 问题:
      1. 用户密码过于简单,容易被破解
      2. 用户登录、修改密码时用明文传输,可以被抓包工具获取
    • 解决思路:
      1. 用户设置、修改密码的时候对密码强度进行等级判定
      2. 数据加密,可使用RSA、MD5等加密算法

    三、跨站脚本攻击(XSS)

    • 问题:
      1. 可能会窃取或操纵客户会话和 cookie,它们可能用于模仿合法用户,从而使黑客能够以该用户身份查看或变更用户记录以及执行事务
      2. 接口数据安全
    • 解决思路:
      1. 在用户提交的时候 判断脚本并且去掉相关信息
      2. https://blog.csdn.net/qq_28945959/article/details/114171863

    四、SQL注入

    • 问题:
      1. 别人利用sql漏洞删库删表。
      2. 在这里插入图片描述
    • 解决思路:
      1. 代码层面最好的办法就是预编译

      2. 确认每种数据的类型,比如数字在数据库中必须使用int类型存储

      3. 规定数据长度,能在一定程度上放置sql注入

      4. 严格限制数据库权限,能最大程度减少sql注入的危害

      5. 过滤参数中含有的一些数据库关键词

      6. 在数据库访问层中不要使用“+”来拼接SQL语句!如:
        
        String sql= “SELECT * FROM USERS WHERE 1=1; if(null !=
        user.getUserName() && !””.equals(user.getUserName())){
        sql += “ and UNAME = ‘”+user.getUserName()+”’”; } 而应使用PreparedStatement。如:
        
        PreparedStatement pstmt = con.prepareStatement(“SELECT * FROM USERS
        WHERE UNAME=?); pstmt.setString(1, “Neeke”);
        如果项目中使用了Hibernate框架,则推荐使用named parameter。如:
        
        String queryString = “from Users where uname like :name”; 冒号后面是一个named
        parameter,我们可以使用Query接口将一个参数绑定到name参数上:
        
        List result = session.createQuery(queryString)
        .setString(“name”, user.getUserName())
        .list();
        

    五、数据重复

    • 问题:
      1. 高并发情况下,多个线程同时插入or修改导致数据重复
    • 解决思路:
      1. 使用分布式锁

    六、数据安全

    • 问题:
      1. 合法用户“注销”后,在未关闭浏览器的情况下,点击浏览器“后退”按钮,可从本地页面缓存中读取数据,绕过了服务端filter过滤。

        • 解决方案:配置filter对存放敏感信息的页面限制页面缓存。如:

          httpResponse.setHeader(“Cache-Control”,“no-cache”);
          httpResponse.setHeader(“Cache-Control”,“no-store”);
          httpResponse.setDateHeader(“Expires”, 0);
          httpResponse.setHeader(“Pragma”,“no-cache”);

      2. 文件上传漏洞。前台仅使用JS对文件后缀做了过滤,这只能针对普通的用户,而恶意攻击者完全可以修改表单去掉JS校验。

        • 解决方案:前台JS过滤加服务器端程序过滤。具体过滤掉哪些文件类型视具体情况而定。

      3. .可执行脚本漏洞。对用户提交的数据未转义,一些用户提交的含有JavaScript脚本的信息被直接输出到页面中从而被浏览器执行

        解决方案:使用org.apache.commons.lang.StringEscapeUtils对用户提交的数据进行转义。如:
        
        @RequestMapping(params=“method=addTopic”,method=RequestMethod.POST)
        public ModelAndView addTopic(HttpServletRequest request,
        HttpServletResponse response, BbsTopic topic) { BaseAdmin user =
        (BaseAdmin) request.getSession().getAttribute(Constant.SESSION_USER);
        topic.setBaseAdmin(user); topic.setTopicDate(new
        Timestamp(System.currentTimeMillis()));
        topic.setTopicContent(StringEscapeUtils.escapeHtml(topic.getTopicContent()));
        topic.setTopicTitle(StringEscapeUtils.escapeHtml(topic.getTopicTitle()));
        this.bbsTopicService.save(topic); return new ModelAndView(new
        RedirectView(“bbs.do?method=topicList&bfid=+ topic.getBfid())); }
        
      4. Java WEB容器默认配置漏洞。如TOMCAT后台管理漏洞,默认用户名及密码登录后可直接上传war文件获取webshell。

        • 解决方案:最好删除,如需要使用它来管理维护,可更改其默认路径,口令及密码。

      5. 日志,建议增加服务器的访问日志,记录来访者的IP,传递参数,对后台操作用户建立日志,记录操作内容,完善日志记录可以帮助你发现潜在危险,找到已经发生的问题。

      6. 僵尸网络暴力破解

      7. 重放攻击

      8. 登陆表单http明文提交

      9. 千万不要乱用数据类型,使用基本数据类型,少用包装类,包装类容易被攻击,不要用string去接受所有类型数据。原则上:是什么类型就用什么类型去接收。

      10. 通过架构设计,添加一层设置处理http参数。一般都是通过aop来实现.比如:对邮件,手机验证对整数最大值验证,对字符串最大长度验证

      11. 点击劫持,大概有两种方式,一是攻击者使用一个透明的iframe,覆盖在一个网页上,然后诱使用户在该页面上进行操作,此时用户将在不值钱的情况下点击透明的iframe页面,二是攻击者使用一张图片覆盖在网页,遮挡网页原有位置的含义。

    展开全文
  • 定义线程安全:当多个线程访问某个类的时候,不管运行时采用何种调度方式或者这些线程如何交替执行并且在这主调代码中不需要任何额外的同步和协同,这个类都能表现出正确的行为, 那么就称这个类为线程安全.并发:并发当...

    定义

    线程安全:当多个线程访问某个类的时候,不管运行时采用何种调度方式或者这些线程如何交替执行并且在

    这主调代码中不需要任何额外的同步和协同,这个类都能表现出正确的行为, 那么就称这个类为线程安全.

    并发:并发当有多个线程在操作时,如果系统只有一个CPU,则它根本不可能真正同时进行一个以上的线程,

    它只能把CPU运行时间划分成若干个时间段,再将时间 段分配给各个线程执行,在一个时间段的线程代码运行时

    ,其它线程处于挂起状。

    简单说明

    线程安全可能是非常复杂的,在没有足够的同步下,多线程执行的顺序是不可预测的,如下在单线程执行时没有任何问题的, 但是多线程执行时可能会出现两个或者多个值一致.

    public class Unsafe {

    int a=0;

    public int getA(){

    return a++;

    }

    }

    因为在多个线程并发中, 对a++进行操作需要三步:读-改-写,首先在主存中读取a的值进入线程工作内存中,然后对a进行++操作, 最后写回主存中.假设线程1,2,3读取a的值都为10,那么线程1,2,3得到a++的值都会是11,因为这个过程中程序都是并行执行, 并不是串行.

    以上最简单的解决方式就是在int前面加上隐式同步锁synchronized,但是这种方式并不高效,每个线程需要执行a++操作, 都需要获取Unsafe实例的锁, 竞争锁失败的线程都会被JVM系统挂起,线程1切换至线程2,我们称之为上下文切换, 这种行为需要系统内核到底层把线程2唤醒, 开销太大.有没有更好方式解决这个问题,不需要劳烦到系统底层呢, 答案是有的,如下

    private AtomicInteger mAtomicInteger=new AtomicInteger();

    private volatile int a=0;

    public Safe(){

    mAtomicInteger.set(a);

    }

    public int getA(){

    for(;;){

    if(mAtomicInteger.compareAndSet(mAtomicInteger.get(), mAtomicInteger.get()+1)){

    return mAtomicInteger.get();

    }

    }

    }

    CAS(CompareAndSwap)是一种比较交换,通过循环来保证线程安全的乐观锁.竞争失败的线程并不会被系统挂起, 而是通过自旋(Self-Spin)不断竞争直到成功返回.

    性能

    主要从可伸缩性,(吞吐率(处理能力)),(服务时间, 延迟时间 (运行速度)) 展开~

    **多线程性能需要建立线程安全基础上, 离开了线程安全线程性能变得没有意义.

    Amdahl定律

    S<=1/(1-a+a/n)

    其中,a为并行计算部分所占比例,n为并行处理结点个数。这样,当1-a=0时,(即没有串行,只有并行)最大加速比s=n;当a=0时(即只有串行,没有并行),最小加速比s=1;当n→∞时,极限加速比s→ 1/(1-a),这也就是加速比的上限。例如,若串行代码占整个代码的25%,则并行处理的总体性能不可能超过4。这一公式已被学术界所接受,并被称做“阿姆达尔定律”。

    根据Amdahl定律可知,程序性能是与串行,并行执行息息相关的,但是糟糕的程序设计并行会带来性能开销,不会提升性能如下说明

    // 并行程序

    public class Person {

    private static void sleep(long time){

    try{

    Thread.sleep(time);

    }catch (Exception e) {

    // TODO: handle exception

    }

    }

    public synchronized void takeATurnRound(){

    //run

    sleep(1000*60*10);

    }

    public static void main(String[]arg){

    Person mPerson=new Person();

    ExecutorService mExecutorService = Executors.newCachedThreadPool();

    for(int i=0;i<3;i++){

    mExecutorService.submit(()->{

    mPerson.takeATurnRound();

    });

    }

    mExecutorService.shutdown();

    }

    }

    //串行程序

    public class Person {

    private static void sleep(long time){

    try{

    Thread.sleep(time);

    }catch (Exception e) {

    // TODO: handle exception

    }

    }

    public void takeATurnRound(){

    sleep(1000*60*10);

    }

    public static void main(String[]arg){

    Person mPerson=new Person();

    mPerson.takeATurnRound();

    mPerson.takeATurnRound();

    mPerson.takeATurnRound();

    }

    }

    上面程序简单演示了一个人跑了三圈,这种并行程序设计严重影响程序性能,可伸缩性极低,不如串行程序,当并发数增加的时候计算能力反而下降了.

    提高可伸缩性

    上面例子可以知道可伸缩最大的威胁就是独占方式的资源锁,所以我们可以通过减少竞争来提升可伸缩性,通过如下方式来减少竞争

    缩小锁的范围

    //错误做法

    public class PasswordStore {

    private HashMapmPasswordMap=new HashMap<>();

    public synchronized boolean storePassword(String name,String password){

    boolean tag=false;

    if(password==null||password.length()<6)

    return tag;

    String mPasswordKey=name;

    String passwordEncord=doCrypto(password);

    try{

    //储存密码

    mPasswordMap.put(mPasswordKey, passwordEncord);

    tag=true;

    }catch(Exception e){

    tag=false;

    }

    return tag;

    }

    //加密

    private String doCrypto(String password){

    return password;

    }

    }

    //正确做法

    public class PasswordStore {

    private HashMapmPasswordMap=new HashMap<>();

    public boolean storePassword(String name,String password){

    boolean tag=false;

    if(password==null||password.length()<6)

    return tag;

    String mPasswordKey=name;

    String passwordEncord=doCrypto(password);

    try{

    synchronized (this) {

    mPasswordMap.put(mPasswordKey, passwordEncord);

    return true;

    }

    }catch(Exception e){

    return false;

    }

    return tag;

    }

    //加密

    private String doCrypto(String password){

    return password;

    }

    }

    通过缩小storePassword方法锁的范围,极大的减少了持有锁执行指令数量,根据Amdahl定律,减少串行代码增加并行代码量可以提升可伸缩性.在实际中其实我们可以使用ConcurrentHashMap来代替HashMap达到线程安全,以及代替HashTable提升锁性能,因为ConcurrentHashMap使用了锁分段Segment等技术, 控制粒度都处理的很好.不得不佩服创造ConcurrentHashMap这位大神Doug Lea!

    减少锁的粒度(锁分解)

    public class LockDecomposed {

    private Listbooks=new ArrayList();

    private Set mEmployee=new HashSet<>();

    public void storeBook(String book){

    /**

    * 错误加锁方式

    * synchronized (this) {

    * books.add(book);

    *}

    */

    synchronized (books) {

    books.add(book);

    }

    }

    public void addStaff(String name){

    /**

    *错误加锁方式

    * synchronized (this) {

    * mEmployee.add(name);

    *}

    */

    synchronized (mEmployee) {

    mEmployee.add(name);

    }

    }

    }

    以上只是简单例子,可能不符合单一职责原则.如果synchronize(this)锁住的对象为添加员工和储存

    书本 时候线程会发生竞争, 竞争时候的线程会被挂起, 然后等待, 等待结束被唤醒在加入系统的线

    程调度队列中,通过锁分解把没必要开销去除

    锁分段

    参考ConcurrentHashMap.

    通过Segment把竞争性缩小

    使用共享锁代替独占锁

    每年春运让人又爱有恨啊,以下模拟下买票系统来说明共享锁和独占锁

    首先进行简单的说明 , 以下用了JDK提供的共享锁 ReentrantReadWriteLock,

    ReentrantReadWriteLock是JDK(concurrent包下的实现类,内部包含ReadLock和 WriteLock)ReadLock和WriteLock 有什么区别呢?WriteLock可以理解为独占锁,ReadLock才是共 享锁的体现, ReentrantReadWriteLock把他们封装在一块,执WriteLock.lock(),TickerServer 内部只有单线程,所有读取线程会被Park挂起,当前线程执行 ReadLock.lock()当前线程会往后看看还有没有跟自己一样以SHAED模式被Park(挂起)起来的线程(存放 AQS里面双向链表),没有往下执行查询逻辑, 有的话会唤醒它(被唤醒的线程做同样的逻辑唤醒它下面的线 程)并行查询票.

    其实啊ReentrantReadWriteLock内部组合着一个很重要的变量Syn, Syn 是 ReentrantReadWriteLock的一个实现AQS的内部类,实际上WriteLock.lock和ReadLock.lock的逻 辑加锁都会交给Syn去完成.Syn会调用父类AQS去完成共享锁和独占锁.AQS可以说是Doug Lea一大杰作, 是 Java JDK的concurrent这个包下的核心类.

    独占锁实现的方式如下

    public class TicketServer {

    private static final List mTicketBeans = new ArrayList<>();

    private static TicketServer mTicketServer = null;

    private Random mRandom = null;

    /**

    * 默认有一万张票

    */

    static {

    for (int i = 0; i < 10000; i++) {

    mTicketBeans.add(new TicketBean(i + 1));

    }

    }

    private TicketServer() {

    mRandom = new Random();

    }

    public List queryTicket() {

    return mTicketBeans;

    }

    public synchronized int queryTicketNumber() {

    System.out.println(" queryTicketNumber current size:" + mTicketBeans.size() + " thread:" + Thread.currentThread().getName());

    try {

    Thread.sleep(10);//做耗时的logic

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    return mTicketBeans.size();

    }

    /**单例模式**/

    public static TicketServer getInstance() {

    if (mTicketServer == null) {

    synchronized (TicketServer.class) {

    if (mTicketServer == null) {

    mTicketServer = new TicketServer();

    }

    }

    }

    return mTicketServer;

    }

    /**加锁模拟买票系统**/

    public synchronized TicketBean buyTicket(String name, double price) {

    int position = -1;

    int size = mTicketBeans.size();

    if (size <= 0) {//查询一下有没有票

    return null;

    } else {

    position = mRandom.nextInt(size);//随机一张票

    }

    TicketBean mTicketBean = mTicketBeans.get(position);

    if (price < mTicketBean.getTicketMoney()) {//判断要付的金额

    return null;

    }

    mTicketBeans.remove(position);//系统移除该票, 改票已经卖出来了

    mTicketBean.setTicketBelong(name);//设置一下票的所属者

    mTicketBean.setTicketKey(Thread.currentThread().getName());

    System.out.println(" buy current size:" + mTicketBeans.size() + " Thread:" + Thread.currentThread());

    return mTicketBean;

    }

    }

    上面独占锁的方式实现卖票模拟器, synchronized的对象是TicketServer, 所以无论是执行买票逻辑还是进行查询剩余的票数的时候内部都只有一个线程在执行,来达到线程安全, 但是这种做法是不提倡,因为这样 做线程的可伸缩性非常死, 提高并发量的时候性能并没有提升.

    /**

    *

    * @author cenxiaozhong

    * 以共享锁模式卖票服务器,也就是说对查询票的数量允许

    * 多个线程进入查询, 但是对卖票必须进行锁定,只有一个线程

    * 可以进行对票操作

    */

    public class TicketServer {

    private Random mRandom = null;

    //票容器

    private static final List mTicketBeans = new ArrayList<>();

    private static TicketServer mTicketServer = null;

    // 原子类

    private static final AtomicReference ATOMIC_REFERENCE = new AtomicReference();

    //共享锁 JDK提供, author Doug Lea

    private ReentrantReadWriteLock mReentrantReadWriteLock = new ReentrantReadWriteLock();

    /**

    * 默认有一万张票

    */

    static {

    for (int i = 0; i < 10000; i++) {

    mTicketBeans.add(new TicketBean(i + 1));

    }

    }

    private TicketServer() {

    mRandom = new Random();

    }

    // 不加锁危险,

    // public List queryTicket() {

    // return mTicketBeans;

    // }

    // 共享方式查询票数

    public int queryTicketNumber() {

    ReentrantReadWriteLock.ReadLock mReadLock = mReentrantReadWriteLock.readLock();// 获取读取lock

    mReadLock.lock();// lock , 读是共享, 也就是 读的时候 其他线程依然可进这段代码进行查询票数

    try {

    try {

    Thread.sleep(10);// 睡一小会

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    System.out.println(" queryTicketNumber current size:" + mTicketBeans.size() + " thread:"

    + Thread.currentThread().getName());

    return mTicketBeans.size();

    } finally {

    mReadLock.unlock();// 一定别忘了unLock 否则出现死锁 具体请查看AQS源码

    }

    }

    //单例模式

    public static TicketServer getInstance() {

    while (true) {

    mTicketServer = ATOMIC_REFERENCE.get();

    if (mTicketServer != null)

    return mTicketServer;

    mTicketServer = new TicketServer();

    if (ATOMIC_REFERENCE.compareAndSet(null, mTicketServer))

    return ATOMIC_REFERENCE.get();

    }

    }

    //买票

    public TicketBean buyTicket(String name, double price) {

    ReentrantReadWriteLock.WriteLock mWriteLock = mReentrantReadWriteLock.writeLock();

    int position = -1;

    mWriteLock.lock();

    try {

    int size = mTicketBeans.size();//简单查询一下票的数量

    if (size <= 0) {

    return null;//没有票了

    } else {

    position = mRandom.nextInt(size);//随机一张票

    }

    TicketBean mTicketBean = mTicketBeans.get(position);

    if (price < mTicketBean.getTicketMoney()) {//简单的判断当前票的价格

    return null;

    }

    mTicketBeans.remove(position);//移除票

    mTicketBean.setTicketBelong(name);//设置票的所属者

    mTicketBean.setTicketKey(Thread.currentThread().getName());

    System.out.println(" buy current size:" + mTicketBeans.size() + " Thread:" + Thread.currentThread());

    return mTicketBean;

    } finally {

    mWriteLock.unlock();//释放写锁

    }

    }

    }

    可以看出查询和买票用了不同锁,共享锁大大提升程序性能. 能避免独占锁尽量避免独占锁

    以下是模拟客户端

    //@author cenxiaozhong

    public class Clients {

    public static void main(String[] args) {

    //线程池

    ExecutorService mExecutorService = Executors.newCachedThreadPool();

    TicketServer mTicketServer = TicketServer.getInstance();

    //线程的计数器

    CountDownLatch mCountDownLatch = new CountDownLatch(1100);

    //记录一下当前时间

    long startTime = System.currentTimeMillis();

    System.out.println("startTime:" + startTime);

    //for循环启动100个线程买票

    for (int i = 0; i < 100; i++) {

    mExecutorService.execute(() -> {

    while (true) {

    sleep(50);//睡一会提高并发量

    TicketBean mTicketBean = mTicketServer.buyTicket(Thread.currentThread().getName(), 800);

    if (mTicketBean != null) {

    continue;

    } else {

    break;

    }

    }

    try {//减一

    mCountDownLatch.countDown();

    } catch (Exception e) {

    e.printStackTrace();

    }

    });

    }

    //启动一千个线程查询还有多少票

    for (int i = 0; i < 1000; i++) {

    mExecutorService.execute(() -> {

    sleep(5);//睡一小会

    int member = mTicketServer.queryTicketNumber();//查询票

    try {

    //线程减一

    mCountDownLatch.countDown();

    } catch (Exception e) {

    e.printStackTrace();

    }

    });

    }

    try {

    //主线程等待 知道1100个线程执行完毕后唤醒

    mCountDownLatch.await();

    //关闭线程池

    mExecutorService.shutdown();

    } catch (InterruptedException e) {

    e.printStackTrace();

    }

    long endTime = System.currentTimeMillis();

    System.out.println("endTime:" + endTime + " extra:" + (endTime - startTime));

    }

    public static void sleep(long time) {

    try {

    Thread.sleep(time);

    } catch (Exception e) {

    e.printStackTrace();

    }

    }

    }

    执行结果

    执行环境Mac os 10.12.2,四核 i7 16G运存

    endTime:1486803316222 extra:6170//使用了共享锁

    endTime:1486805339097 extra:17140//使用了独占锁

    可以看出来共享锁比独占锁效率高出了接近三倍, 其实不止, 会随之查询并发数增大而不同,很大一

    个原因是因为独占锁进行查询的时候会排斥所有线程.

    在高并发情况不使用对象池(享元模式).享元模式对资源重新利用,用空间换时间, 提高了性能.但是在并发情况反而带来开销.

    * Return a new Message instance from the global pool. Allows us to

    * avoid allocating new objects in many cases.

    */

    public static Message obtain() {

    synchronized (sPoolSync) {

    if (sPool != null) {

    Message m = sPool;

    sPool = m.next;

    m.next = null;

    m.flags = 0; // clear in-use flag

    sPoolSize--;

    return m;

    }

    }

    return new Message();

    }

    以上可以看出从对象池获取对象是必须要加锁,不加锁会出现不同线程拿到相同对象Message,这是不允许的,加锁意味着在多线程访问中会出现阻塞, 阻塞,唤醒等开销足以new 出数百个Message对象了.所以在并发频率很高时候不使用对象池.

    等等.

    展开全文
  • 最近公司做的一个项目,要在客户机上部署。如何才能防止对方的技术人员对war包里的内容进行反编译? 如果使用代码混淆的话,混淆后的代码如何使用? 还有就是怎么防止对方多地部署,或者说在多台机器上部署?
  • 安全性问题线程安全的本质是正确性,而正确性的含义是程序按照预期执行理论上线程安全的程序,应该要避免出现可见性问题(CPU缓存)、原子性问题(线程切换)和有序性问题(编译优化)需要分析是否存在线程安全问题的场景...

    96c80c80d4a91597e27464f49d965ed7.png

    一. 安全性问题

    线程安全的本质是正确性,而正确性的含义是程序按照预期执行

    理论上线程安全的程序,应该要避免出现可见性问题(CPU缓存)、原子性问题(线程切换)和有序性问题(编译优化)

    需要分析是否存在线程安全问题的场景:存在共享数据且数据会发生变化,即有多个线程会同时读写同一个数据

    针对该理论的解决方案:不共享数据,采用线程本地存储(Thread Local Storage,TLS);不变模式

    Ⅰ. 数据竞争

    数据竞争(Data Race):多个线程同时访问同一数据,并且至少有一个线程会写这个数据

    1. add

    private static final int MAX_COUNT = 1_000_000;

    private long count = 0;

    // 非线程安全

    public void add() {

    int index = 0;

    while (++index < MAX_COUNT) {

    count += 1;

    }

    }

    2. add + synchronized

    private static final int MAX_COUNT = 1_000_000;

    private long count = 0;

    public synchronized long getCount() {

    return count;

    }

    public synchronized void setCount(long count) {

    this.count = count;

    }

    // 非线程安全

    public void add() {

    int index = 0;

    while (++index < MAX_COUNT) {

    setCount(getCount() + 1);

    }

    }

    假设count=0,当两个线程同时执行getCount(),都会返回0

    两个线程执行getCount()+1,结果都是1,最终写入内存是1,不符合预期,这种情况为竟态条件

    Ⅱ. 竟态条件

    竟态条件(Race Condition):程序的执行结果依赖于线程执行的顺序

    在并发环境里,线程的执行顺序是不确定的

    如果程序存在竟态条件问题,那么意味着程序的执行结果是不确定的

    1. 转账

    public class Account {

    private int balance;

    // 非线程安全,存在竟态条件,可能会超额转出

    public void transfer(Account target, int amt) {

    if (balance > amt) {

    balance -= amt;

    target.balance += amt;

    }

    }

    }

    Ⅲ. 解决方案

    面对数据竞争和竟态条件问题,可以通过互斥的方案来实现线程安全,互斥的方案可以统一归为锁

    二. 活跃性问题

    活跃性问题:某个操作无法执行下去,包括三种情况:死锁、活锁、饥饿

    Ⅰ. 死锁

    发生死锁后线程会相互等待,表现为线程永久阻塞

    解决死锁问题的方法是规避死锁(破坏发生死锁的条件之一)

    互斥:不可破坏,锁定目的就是为了互斥

    占有且等待:一次性申请所有需要的资源

    不可抢占:当线程持有资源A,并尝试持有资源B时失败,线程主动释放资源A

    循环等待:将资源编号排序,线程申请资源时按递增(或递减)的顺序申请

    Ⅱ. 活锁

    活锁:线程并没有发生阻塞,但由于相互谦让,而导致执行不下去

    解决方案:在谦让时,尝试等待一个随机时间(分布式一致算法Raft也有采用)

    Ⅲ. 饥饿

    饥饿:线程因无法访问所需资源而无法执行下去

    线程的优先级是不相同的,在CPU繁忙的情况下,优先级低的线程得到执行的机会很少,可能发生线程饥饿

    持有锁的线程,如果执行的时间过长(持有的资源不释放),也有可能导致饥饿问题

    解决方案

    保证资源充足

    公平地分配资源(公平锁) – 比较可行

    避免持有锁的线程长时间执行

    三. 性能问题

    锁的过度使用可能会导致串行化的范围过大,这会影响多线程优势的发挥(并发程序的目的就是为了提升性能)

    尽量减少串行,假设串行百分比为5%,那么多核多线程相对于单核单线程的提升公式(Amdahl定律)

    S=1/((1-p)+p/n),n为CPU核数,p为并行百分比,(1-p)为串行百分比

    假如p=95%,n无穷大,加速比S的极限为20,即无论采用什么技术,最高只能提高20倍的性能

    Ⅰ. 解决方案

    无锁算法和数据结构

    线程本地存储(Thread Local Storage,TLS)

    写入时复制(Copy-on-write)

    乐观锁

    JUC中的原子类

    Disruptor(无锁的内存队列)

    减少锁持有的时间,互斥锁的本质是将并行的程序串行化,要增加并行度,一定要减少持有锁的时间

    使用细粒度锁,例如JUC中的ConcurrentHashMap(分段锁)

    使用读写锁,即读是无锁的,只有写才会互斥的

    Ⅱ. 性能指标

    吞吐量:在单位时间内能处理的请求数量,吞吐量越高,说明性能越好

    延迟:从发出请求到收到响应的时间,延迟越小,说明性能越好

    并发量:能同时处理的请求数量,一般来说随着并发量的增加,延迟也会增加,所以延迟一般是基于并发量来说的

    写在最后

    第一:看完点赞,感谢您的认可;

    ...

    第二:随手转发,分享知识,让更多人学习到;

    ...

    第三:记得点关注,每天更新的!!!

    ...

    展开全文
  • 假设我在旧/遗留Java库中有特定代码:public class JavaClass {private String notNullString;private String nullableString;private String unannotatedString;public JavaClass(@NotNull String notNullString,@...

    假设我在旧/遗留Java库中有特定代码:

    public class JavaClass {

    private String notNullString;

    private String nullableString;

    private String unannotatedString;

    public JavaClass(@NotNull String notNullString,

    @Nullable String nullableString,

    String unannotatedString) {

    this.notNullString = notNullString;

    this.nullableString = nullableString;

    this.unannotatedString = unannotatedString;

    }

    @NotNull

    public String getNotNullString() {

    return notNullString;

    }

    @Nullable

    public String getNullableString() {

    return nullableString;

    }

    public String getUnannotatedString() {

    return unannotatedString;

    }

    }

    前两个参数使用@NotNull和@Nullable注释正确注释(使用jetbrains.annotations) . 第三个( unnanotatedString )没有正确的注释 .

    当我在我的Kotlin代码中使用这个类并将所有构造函数参数设置为非null值时,一切都很好:

    val foo = JavaClass("first string", "second string", "third string")

    println("Value1: ${foo.notNullString.length}")

    println("Value2: ${foo.nullableString?.length}")

    println("Value3: ${foo.unannotatedString.length}")

    第一个值是非null,所以我可以在没有安全调用的情况下访问它 . 第二个值我需要使用安全调用(nullableString?.length),如果没有,我有一个编译时错误,到目前为止一直很好 . 在第三个值(unannotatedString)我可以在没有安全调用的情况下使用它,它编译得很好 .

    但是当我将第三个参数设置为“null”时,我没有得到编译时错误(不需要安全调用,只有运行时NullPointerException:

    val bar = JavaClass("first string", "second string", null)

    println("Value4: ${bar.unannotatedString.length}") // throws NPE

    这是预期的行为吗? Kotlin的编译器是否将带注释的Java方法与使用@NotNull注释的方法相同?

    展开全文
  • java web 项目中的安全性问题(spring cloud版) 登录爆破 跨站脚本攻击(XSS注入) 密码安全
  • 《深入java虚拟机》 java安全性java的安全模型的结构特点使其适用于网络环境技术。软件可以通过网络下载并在本地运行。 比如java applet,用户一打开网页。applet的class文件就会被自动下载,很...
  • java web项目安全设计

    千次阅读 2018-04-16 16:22:14
    登录页面增加一次图形验证码–仅能验证一次,验证后从session立即删除该key 禁止同一账户多处登录–以shiro框架做权限管理为例,实现方式参考我的另一篇文章《shiro框架实现单点登录》 sessionId不能固...
  • 在一个安卓App项目中访问java后台接口,对于请求接口安全性跟用户登录状态验证.接口安全性采用签名的方式用户登录状态采用token的方式具体实现思路如下(小小菜鸟欢迎指正) 1.java后台安全性配置:secret(密钥),appId...
  • Java项目安全发布--Jar包(class)加解密实践

    千次阅读 多人点赞 2020-09-15 00:04:45
    项目需要在客户机器上进行本地部署,这就涉及到自家代码的安全性问题。需要保证以下几点: 代码不能被他人"窃取"(保证源码不可见) 不能通过已有项目复制一份系统出来(即使源码不可见) 如果是自己...
  • 我将在我的Javascript前端Spring MVC项目(用户管理管理员web应用程序)中使用Spring安全性我试图弄清楚是否有任何安全性好处将这些前端html代码特别放在与我的后端代码相同的服务器中的jsp文件中,所以我可以利用某些...
  • 在设计项目时,考虑到系统的高效性、数据的安全性,前端的核心功能只是展示数据给用户看,而真正的逻辑应当放到后台去处理。为了保证数据传输的轻便和效率,前台和后台尽可能设计为固定数据格式来处理,比如将获取的...
  • android原生开源项目 作为我在具有开放源代码开发模型的企业软件公司担任高级产品营销经理的角色的一部分,我定期发布有关产品营销人员,经理和其他影响者的开源社区,市场和行业趋势的更新。 以下是该更新中我和...
  • 但是代理这种关系不是JAVA语言自带的,是组合和继承两者结合的一种特殊关系。代理中,我们需要把成员对象放到需要构造的类当中,不管是组合还是继承,我们在需要构造的类当中,会暴露这个成员对象的所有方法,所以...
  • Java的代码质量和安全性 该SonarSource项目是Java项目的代码分析器。 有关Java功能分析的信息可。 产品特点 500多个规则(包括100多个错误检测规则和300多个代码气味) 指标(复杂度,行数等) 导入 有用的链接 ...
  • Java安全性 该存储库包含几个Java Web应用程序和命令行应用程序,涵盖了不同的安全主题。 看看我的和涵盖了该存储库中的大多数应用程序。 要求 (强烈建议使用,某些演示可能无法在其他浏览器中正常运行) Web应用...
  • java后台组长需要考虑后台代码的性能、可扩展性、稳定性、安全性。 需要注重研发团队文化建设,组织文体活动等。 需要注重人才的培养,比如组织代码评审,提高团队代码质量,组织前沿技术研讨会议,做技术分享,...
  • Java(web)项目安全漏洞及解决方式【面试+工作】

    万次阅读 多人点赞 2018-05-13 09:49:19
    Java(web)项目安全漏洞及解决方式【面试+工作】一.安全性问题层次关系大家经常会听到看到很多很多有关安全性方面的信息,可以说形形色色,对于在网络安全方面不太专业的同志来说,有点眼花缭乱,理不出头绪。在...
  • 前端多次调用(伪幂等问题) ...(安全等级高则可以选择redis分布式锁机制) rpc调用幂等问题 rpc的默认重试机制会导致调用方在规定超时时间和次数内反复调用被调用方 1.禁用重试(不合理) 2.加大
  • 目前项目有个安全性问题需要解决! 场景 :用google chrome查看系统登录前后的jsessionid值是一样的。 需求:在系统登录前后这个jsessionid要不一样。 尝试方法一: 在登录页面加入如下代码: request....
  • 具有以下特性:简单、面向对象、分布、解释、可靠、安全、平台无关、可移植、高性能、多线程、动态等特点。面向过程和面向对象可以用以下两种公式表示:面向过程:程序=算法+数据面向对象:程序=对象+属性...
  • 安全性问题层次关系二.安全性问题的本质三.安全漏洞及处理方式1、SQL注入攻击2、XSS跨站脚本攻击3、CSRF跨站请求伪造漏洞防护4、URL链接注入漏洞防护5、会话COOKIE中缺少HttpOnly防护6、点击劫持漏洞(Clickjacking)...
  • -----------------------------------java线程并发及并发安全性问题------------------------------------ 并发 互联网的项目中存在着大量的并发案例。如:卖火车票,电商网站。 范例:火车站有10张票,4个窗口...
  • spark-pac4j项目是用于Sparkjava Web应用程序和Web服务的简单而强大的安全性库,它支持身份验证和授权,还支持注销和会话固定和CSRF保护等高级功能。 它基于Java 8,Spark 2.9和v4 。 它在Apache 2许可下可用。 ...
  • java安全性和数据库设计注意事项

    千次阅读 2016-07-09 20:18:07
    先说说数据库设计的注意事项,最近一个项目中,数据库表结构的设计都是由我来设计,在设计的过程中,并没有考虑到性能的因素,所以在规定字段类型的时候,为了省事把许多字段一律设置成varchar类型,varchar类型即为...
  • 在这里讲一下APP与后端交互的安全性。没有AUTH的验证最简单的验证机制是通过session来存储认证信息的,但这个不便于客户端存储,而且有不能跨域请求认证的缺点。大致流程:用户登录(输入账户密码)后端验证验证通过则...
  • 我们开发项目时要经常和数据库打交道,用户的每一个操作基本上都和...为了保证数据的安全性,所以要保证同一时刻只能允许一个用户对数据库的同一个字段进行操作。要实现上述的描述,以下两种方法可以很好的解决该问题。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,228
精华内容 891
关键字:

java项目安全性

java 订阅